<commit_before>//! The `leac` compiler command line utility.

#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate docopt;
extern crate rustc_serialize;
extern crate bincode;
extern crate term;
extern crate lea_compiler as compiler;
extern crate lea_parser as parser;
extern crate lea;

use parser::span::DummyTerm;
use compiler::{CompileConfig, FnData};

use rustc_serialize::json;
use bincode::{EncodingError, SizeLimit};

use std::io::{self, stdin, stderr, stdout, Read, Write};
use std::fs::File;
use std::path::Path;

#[derive(Debug, RustcDecodable)]
#[allow(non_camel_case_types)]
enum Encoding {
    json,
    bin,
    debug,
}

impl Encoding {
    pub fn encode<W: Write>(&self, fndata: &FnData, wr: &mut W)
    -> io::Result<()> {
        match *self {
            Encoding::json => {
                match json::encode(fndata) {
                    Ok(s) => Ok(try!(write!(wr, "{}", &s))),
                    Err(_) => Err(io::Error::new(io::ErrorKind::Other, "json encoding error")),
                }
            }
            Encoding::bin => {
                match bincode::encode_into(fndata, wr, SizeLimit::Infinite) {
                    Ok(_) => Ok(()),
                    Err(EncodingError::IoError(e)) => Err(e),
                    Err(EncodingError::SizeLimit) => Err(io::Error::new(io::ErrorKind::Other, "size limit reached")),
                }
            }
            Encoding::debug => {
                write!(wr, "{:#?}\n", fndata)
            }
        }
    }
}

docopt!(Args derive Debug, "
The Lea compiler

Usage:
    leac ( --help | --version )
    leac [-o <out>] [-e <enc>] [--] <file>
    leac ( -p | --pretty ) [--] <file>

Options:
    -h, --help                  Show this help.
    -v, --version               Show the version of the Lea package.
    -p, --pretty                Pretty print the source code instead of compiling it.
    -o <out>, --out <out>       Write output to <out> (`-` to write to stdout).
    -e <enc>, --encoding <enc>  The encoding to use for writing the compiled code.

By default, leac will write the compiled code to stdout. If stdout is a terminal, leac will print \
it using the `debug` encoding. Otherwise, leac will encode the compilation result in a binary \
form (`bin` encoding).
", flag_encoding: Option<Encoding>, flag_out: Option<String>);

/// Opens a terminal that writes to stderr. If stderr couldn't be opened as a terminal, creates a
/// `DummyTerm` that writes to stderr instead.
fn stderr_term() -> Box<term::StderrTerminal> {
    term::stderr().unwrap_or_else(|| Box::new(DummyTerm(io::stderr())))
}

/// Compiles a piece of code. Prints all errors / warnings to stderr, using color if stderr is a
/// terminal.
fn compile(code: &str, filename: &str) -> io::Result<Option<FnData>> {
    let mut fmt_target = stderr_term();
    let fmt_target = &mut *fmt_target;

    match compiler::compile_str(code, filename, &CompileConfig::default()) {
        Err(e) => {
            try!(e.format(code, filename, fmt_target));
            Ok(None)
        },
        Ok(output) => {
            let warns = output.warns;
            if warns.len() > 0 {
                for w in warns {
                    try!(w.format(code, filename, fmt_target));
                }
            }

            Ok(Some(output.mainproto))
        }
    }
}

fn read_file(filename: &str) -> io::Result<String> {
    let mut s = String::new();
    let mut file = try!(File::open(&Path::new(filename)));
    try!(file.read_to_string(&mut s));

    Ok(s)
}

#[allow(dead_code)]     // TODO write tests
fn main() {
    match Args::docopt().decode::<Args>() {
        Err(e) => {
            println!("{}", e);
        }
        Ok(args) => {
            match args {
                Args { flag_version: true, .. } => {
                    println!("Lea {}", lea::version_str());
                }
                Args { arg_file, flag_out, .. } => {
                    // Read input
                    let mut code = String::new();
                    let source_name;
                    if arg_file == "-" {
                        stdin().read_to_string(&mut code).unwrap();
                        source_name = "<stdin>".to_owned();
                    } else {
                        source_name = arg_file;
                        code = match read_file(&source_name) {
                            Ok(content) => content,
                            Err(e) => {
                                writeln!(stderr(), "{}", e).unwrap();
                                return;
                            }
                        }
                    }

                    // Open output
                    let mut out: Box<Write>;
                    match flag_out.as_ref().map(|s| s.as_ref()) {
                        None | Some("-") => {
                            out = Box::new(stdout()) as Box<Write>;
                        }
                        Some(s) => {
                            let f = match File::create(&Path::new(s)) {
                                Ok(f) => f,
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                            };

                            out = Box::new(f) as Box<Write>;
                        }
                    }

                    let enc = args.flag_encoding.unwrap_or(Encoding::bin);

                    match compile(&code, &source_name).unwrap() {
                        Some(fndata) => {
                            // serialize to `out`, except if `out` is a terminal and we defaulted to `-` (TODO)
                            match enc.encode(&fndata, &mut out) {
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                                _ => {}
                            }
                        }
                        None => {}
                    }
                }
            }
        }
    }
}
<commit_msg>Fix breakage after bincode update<commit_after>//! The `leac` compiler command line utility.

#![feature(plugin)]
#![plugin(docopt_macros)]

extern crate docopt;
extern crate rustc_serialize;
extern crate bincode;
extern crate term;
extern crate lea_compiler as compiler;
extern crate lea_parser as parser;
extern crate lea;

use parser::span::DummyTerm;
use compiler::{CompileConfig, FnData};

use rustc_serialize::json;
use bincode::SizeLimit;
use bincode::rustc_serialize::EncodingError;

use std::io::{self, stdin, stderr, stdout, Read, Write};
use std::fs::File;
use std::path::Path;

#[derive(Debug, RustcDecodable)]
#[allow(non_camel_case_types)]
enum Encoding {
    json,
    bin,
    debug,
}

impl Encoding {
    pub fn encode<W: Write>(&self, fndata: &FnData, wr: &mut W)
    -> io::Result<()> {
        match *self {
            Encoding::json => {
                match json::encode(fndata) {
                    Ok(s) => Ok(try!(write!(wr, "{}", &s))),
                    Err(_) => Err(io::Error::new(io::ErrorKind::Other, "json encoding error")),
                }
            }
            Encoding::bin => {
                match bincode::rustc_serialize::encode_into(fndata, wr, SizeLimit::Infinite) {
                    Ok(_) => Ok(()),
                    Err(EncodingError::IoError(e)) => Err(e),
                    Err(EncodingError::SizeLimit) => Err(io::Error::new(io::ErrorKind::Other, "size limit reached")),
                }
            }
            Encoding::debug => {
                write!(wr, "{:#?}\n", fndata)
            }
        }
    }
}

docopt!(Args derive Debug, "
The Lea compiler

Usage:
    leac ( --help | --version )
    leac [-o <out>] [-e <enc>] [--] <file>
    leac ( -p | --pretty ) [--] <file>

Options:
    -h, --help                  Show this help.
    -v, --version               Show the version of the Lea package.
    -p, --pretty                Pretty print the source code instead of compiling it.
    -o <out>, --out <out>       Write output to <out> (`-` to write to stdout).
    -e <enc>, --encoding <enc>  The encoding to use for writing the compiled code.

By default, leac will write the compiled code to stdout. If stdout is a terminal, leac will print \
it using the `debug` encoding. Otherwise, leac will encode the compilation result in a binary \
form (`bin` encoding).
", flag_encoding: Option<Encoding>, flag_out: Option<String>);

/// Opens a terminal that writes to stderr. If stderr couldn't be opened as a terminal, creates a
/// `DummyTerm` that writes to stderr instead.
fn stderr_term() -> Box<term::StderrTerminal> {
    term::stderr().unwrap_or_else(|| Box::new(DummyTerm(io::stderr())))
}

/// Compiles a piece of code. Prints all errors / warnings to stderr, using color if stderr is a
/// terminal.
fn compile(code: &str, filename: &str) -> io::Result<Option<FnData>> {
    let mut fmt_target = stderr_term();
    let fmt_target = &mut *fmt_target;

    match compiler::compile_str(code, filename, &CompileConfig::default()) {
        Err(e) => {
            try!(e.format(code, filename, fmt_target));
            Ok(None)
        },
        Ok(output) => {
            let warns = output.warns;
            if warns.len() > 0 {
                for w in warns {
                    try!(w.format(code, filename, fmt_target));
                }
            }

            Ok(Some(output.mainproto))
        }
    }
}

fn read_file(filename: &str) -> io::Result<String> {
    let mut s = String::new();
    let mut file = try!(File::open(&Path::new(filename)));
    try!(file.read_to_string(&mut s));

    Ok(s)
}

#[allow(dead_code)]     // TODO write tests
fn main() {
    match Args::docopt().decode::<Args>() {
        Err(e) => {
            println!("{}", e);
        }
        Ok(args) => {
            match args {
                Args { flag_version: true, .. } => {
                    println!("Lea {}", lea::version_str());
                }
                Args { arg_file, flag_out, .. } => {
                    // Read input
                    let mut code = String::new();
                    let source_name;
                    if arg_file == "-" {
                        stdin().read_to_string(&mut code).unwrap();
                        source_name = "<stdin>".to_owned();
                    } else {
                        source_name = arg_file;
                        code = match read_file(&source_name) {
                            Ok(content) => content,
                            Err(e) => {
                                writeln!(stderr(), "{}", e).unwrap();
                                return;
                            }
                        }
                    }

                    // Open output
                    let mut out: Box<Write>;
                    match flag_out.as_ref().map(|s| s.as_ref()) {
                        None | Some("-") => {
                            out = Box::new(stdout()) as Box<Write>;
                        }
                        Some(s) => {
                            let f = match File::create(&Path::new(s)) {
                                Ok(f) => f,
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                            };

                            out = Box::new(f) as Box<Write>;
                        }
                    }

                    let enc = args.flag_encoding.unwrap_or(Encoding::bin);

                    match compile(&code, &source_name).unwrap() {
                        Some(fndata) => {
                            // serialize to `out`, except if `out` is a terminal and we defaulted to `-` (TODO)
                            match enc.encode(&fndata, &mut out) {
                                Err(e) => {
                                    writeln!(stderr(), "{}", e).unwrap();
                                    return;
                                }
                                _ => {}
                            }
                        }
                        None => {}
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use raft::raftpb::{HardState, ConfState, Entry, Snapshot};
use protobuf;
use raft::errors::Result;
use raft::errors::{Error, StorageError};

#[derive(Debug, Clone)]
pub struct RaftState {
    hard_state: HardState,
    conf_state: ConfState,
}

pub trait Storage {
    fn initial_state(&self) -> Result<RaftState>;
    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]>;
    fn term(&self, idx: u64) -> Result<u64>;
    fn first_index(&self) -> Result<u64>;
    fn last_index(&self) -> Result<u64>;
    fn snapshot(&self) -> Result<Snapshot>;
}

pub struct MemStorage {
    hard_state: HardState,
    snapshot: Snapshot,
    entries: Vec<Entry>,
}

impl MemStorage {
    pub fn new() -> MemStorage {
        MemStorage {
            // When starting from scratch populate the list with a dummy entry at term zero.
            entries: vec![Entry::new()],
            hard_state: HardState::new(),
            snapshot: Snapshot::new(),
        }
    }

    pub fn set_hardstate(&mut self, hs: HardState) {
        self.hard_state = hs;
    }

    fn inner_last_index(&self) -> u64 {
        return self.entries[0].get_Index() + self.entries.len() as u64 - 1;
    }

    fn limit_size(entries: &[Entry], max: u64) -> Result<&[Entry]> {
        if entries.len() == 0 {
            return Ok(entries);
        }

        let mut size = protobuf::Message::compute_size(&entries[0]) as u64;
        let mut limit = 1u64;
        while limit < entries.len() as u64 {
            size += protobuf::Message::compute_size(&entries[limit as usize]) as u64;
            if size > max {
                break;
            }
            limit += 1;
        }
        let ents = &entries[..limit as usize];
        Ok(ents)
    }
}

impl Storage for MemStorage {
    fn initial_state(&self) -> Result<RaftState> {
        Ok(RaftState {
            hard_state: self.hard_state.clone(),
            conf_state: self.snapshot.get_metadata().get_conf_state().clone(),
        })
    }

    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]> {
        let offset = self.entries[0].get_Index();
        if low <= offset {
            return Err(Error::Store(StorageError::Compacted));
        }

        if high > self.inner_last_index() + 1 {
            panic!("index out of bound")
        }
        // only contains dummy entries.
        if self.entries.len() == 1 {
            return Err(Error::Store(StorageError::Unavailable));
        }

        let lo = (low - offset) as usize;
        let hi = (high - offset) as usize;
        let ents: &[Entry] = &self.entries[lo..hi];
        return MemStorage::limit_size(ents, max_size);
    }

    fn term(&self, idx: u64) -> Result<u64> {
        let offset = self.entries[0].get_Index();
        if idx < offset {
            return Err(Error::Store(StorageError::Compacted));
        }
        Ok(self.entries[(idx - offset) as usize].get_Term())
    }

    fn first_index(&self) -> Result<u64> {
        Ok(self.entries[0].get_Index() + 1)
    }

    fn last_index(&self) -> Result<u64> {
        Ok(self.inner_last_index())
    }

    fn snapshot(&self) -> Result<Snapshot> {
        unimplemented!()
    }
}
<commit_msg>raft: implement apply_snapshot and snapshot method.<commit_after>use raft::raftpb::{HardState, ConfState, Entry, Snapshot};
use protobuf;
use raft::errors::Result;
use raft::errors::{Error, StorageError};

#[derive(Debug, Clone)]
pub struct RaftState {
    hard_state: HardState,
    conf_state: ConfState,
}

pub trait Storage {
    fn initial_state(&self) -> Result<RaftState>;
    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]>;
    fn term(&self, idx: u64) -> Result<u64>;
    fn first_index(&self) -> Result<u64>;
    fn last_index(&self) -> Result<u64>;
    fn snapshot(&self) -> Result<&Snapshot>;
}

pub struct MemStorage {
    hard_state: HardState,
    snapshot: Snapshot,
    entries: Vec<Entry>,
}

impl MemStorage {
    pub fn new() -> MemStorage {
        MemStorage {
            // When starting from scratch populate the list with a dummy entry at term zero.
            entries: vec![Entry::new()],
            hard_state: HardState::new(),
            snapshot: Snapshot::new(),
        }
    }

    pub fn set_hardstate(&mut self, hs: HardState) {
        self.hard_state = hs;
    }

    fn inner_last_index(&self) -> u64 {
        return self.entries[0].get_Index() + self.entries.len() as u64 - 1;
    }

    fn limit_size(entries: &[Entry], max: u64) -> Result<&[Entry]> {
        if entries.len() == 0 {
            return Ok(entries);
        }

        let mut size = protobuf::Message::compute_size(&entries[0]) as u64;
        let mut limit = 1u64;
        while limit < entries.len() as u64 {
            size += protobuf::Message::compute_size(&entries[limit as usize]) as u64;
            if size > max {
                break;
            }
            limit += 1;
        }
        let ents = &entries[..limit as usize];
        Ok(ents)
    }

    fn apply_snapshot(&mut self, snapshot: Snapshot) ->Result<()> {
	let mut e = Entry::new();
	e.set_Term(snapshot.get_metadata().get_term());
	e.set_Index(snapshot.get_metadata().get_index());
	self.entries = vec![e];
	self.snapshot  = snapshot;
	Ok(())
    }
}

impl Storage for MemStorage {
    fn initial_state(&self) -> Result<RaftState> {
        Ok(RaftState {
            hard_state: self.hard_state.clone(),
            conf_state: self.snapshot.get_metadata().get_conf_state().clone(),
        })
    }

    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]> {
        let offset = self.entries[0].get_Index();
        if low <= offset {
            return Err(Error::Store(StorageError::Compacted));
        }

        if high > self.inner_last_index() + 1 {
            panic!("index out of bound")
        }
        // only contains dummy entries.
        if self.entries.len() == 1 {
            return Err(Error::Store(StorageError::Unavailable));
        }

        let lo = (low - offset) as usize;
        let hi = (high - offset) as usize;
        let ents: &[Entry] = &self.entries[lo..hi];
        return MemStorage::limit_size(ents, max_size);
    }

    fn term(&self, idx: u64) -> Result<u64> {
        let offset = self.entries[0].get_Index();
        if idx < offset {
            return Err(Error::Store(StorageError::Compacted));
        }
        Ok(self.entries[(idx - offset) as usize].get_Term())
    }

    fn first_index(&self) -> Result<u64> {
        Ok(self.entries[0].get_Index() + 1)
    }

    fn last_index(&self) -> Result<u64> {
        Ok(self.inner_last_index())
    }

    fn snapshot(&self) -> Result<&Snapshot> {
	Ok(&self.snapshot)
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
        let attr = (
            String::from("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        // Continue execution
        true
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");

            miri::eval_main(tcx, entry_def_id, self.miri_config.clone());
        });

        compiler.session().abort_if_errors();

        // Don't continue execution
        false
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUST_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUST_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUST_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUST_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUST_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUST_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`.
    // Do this late, so we really only apply this to miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUST_CTFE_BACKTRACE", &var);
        }
    }
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \
                     build-time specify `RUST_SYSROOT` env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "--" => {
                    after_dashdash = true;
                }
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot and let rustc know about it.
    let sysroot_flag = String::from("--sysroot");
    if !rustc_args.contains(&sysroot_flag) {
        rustc_args.push(sysroot_flag);
        rustc_args.push(find_sysroot());
    }
    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig { validate, args: miri_args };
    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<commit_msg>Reintroduce prepending the input file name to the miri arguments<commit_after>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
        let attr = (
            String::from("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        // Continue execution
        true
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            miri::eval_main(tcx, entry_def_id, config);
        });

        compiler.session().abort_if_errors();

        // Don't continue execution
        false
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUST_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUST_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUST_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUST_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUST_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUST_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`.
    // Do this late, so we really only apply this to miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUST_CTFE_BACKTRACE", &var);
        }
    }
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \
                     build-time specify `RUST_SYSROOT` env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "--" => {
                    after_dashdash = true;
                }
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot and let rustc know about it.
    let sysroot_flag = String::from("--sysroot");
    if !rustc_args.contains(&sysroot_flag) {
        rustc_args.push(sysroot_flag);
        rustc_args.push(find_sysroot());
    }
    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig { validate, args: miri_args };
    let result = rustc_driver::report_ices_to_stderr_if_any(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use std::path::PathBuf;
use std::env;

use rustc::session::Session;
use rustc_metadata::cstore::CStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use syntax::ast;

struct MiriCompilerCalls {
    default: Box<RustcDefaultCalls>,

    /// Whether to enforce the validity invariant.
    validate: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        codegen_backend: &CodegenBackend,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(
        self: Box<Self>,
        sess: &Session,
        matches: &getopts::Matches,
    ) -> CompileController<'a> {
        let this = *self;
        let mut control = this.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        let validate = this.validate;
        control.after_analysis.callback =
            Box::new(move |state| after_analysis(state, validate));
        control.after_analysis.stop = Compilation::Stop;
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (
        String::from("miri"),
        syntax::feature_gate::AttributeType::Whitelisted,
    );
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(
    state: &mut CompileState<'a, 'tcx>,
    validate: bool,
) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a> {
            tcx: TyCtxt<'a, 'tcx, 'tcx>,
            state: &'a CompileState<'a, 'tcx>,
            validate: bool,
        };
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::ItemKind::Fn(.., body_id) = i.node {
                    if i.attrs.iter().any(|attr| {
                        attr.name() == "test"
                    })
                    {
                        let did = self.tcx.hir.body_owner_def_id(body_id);
                        println!(
                            "running test: {}",
                            self.tcx.def_path_debug_str(did),
                        );
                        miri::eval_main(self.tcx, did, self.validate);
                        self.state.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(
            &mut Visitor { tcx, state, validate }
        );
    } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        miri::eval_main(tcx, entry_def_id, validate);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn init_loggers() {
    // Notice that our `extern crate log` is NOT the same as rustc's!  So we have to initialize
    // them both.
    // First, miri.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // Now, change the RUST_LOG env var to control rustc's logger.
    // If MIRI_LOG is set and RUST_LOG is not, set RUST_LOG.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUST_LOG") == Err(env::VarError::NotPresent) {
            // We try to be a bit clever here: If MIRI_LOG is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related.  Only if MIRI_LOG contains `module=level`, we just
            // use the same value for RUST_LOG.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if var.contains('=') {
                env::set_var("RUST_LOG", &var);
            } else {
                env::set_var("RUST_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            }
        }
    }
    rustc_driver::init_rustc_env_logger();
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "Could not find sysroot. Either set MIRI_SYSROOT at run-time, or at \
                     build-time specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

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

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    let mut validate = true;
    args.retain(|arg| {
        match arg.as_str() {
            "-Zmiri-disable-validation" => {
                validate = false;
                false
            },
            _ => true
        }
    });

    let result = rustc_driver::run(move || {
        rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
            default: Box::new(RustcDefaultCalls),
            validate,
        }), None, None)
    });
    std::process::exit(result as i32);
}
<commit_msg>when using MIRI_LOG, avoid logging for what rustc does before miri gets started<commit_after>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use std::path::PathBuf;
use std::env;

use rustc::session::Session;
use rustc_metadata::cstore::CStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use syntax::ast;

struct MiriCompilerCalls {
    default: Box<RustcDefaultCalls>,

    /// Whether to enforce the validity invariant.
    validate: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        codegen_backend: &CodegenBackend,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(
        self: Box<Self>,
        sess: &Session,
        matches: &getopts::Matches,
    ) -> CompileController<'a> {
        let this = *self;
        let mut control = this.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        let validate = this.validate;
        control.after_analysis.callback =
            Box::new(move |state| after_analysis(state, validate));
        control.after_analysis.stop = Compilation::Stop;
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (
        String::from("miri"),
        syntax::feature_gate::AttributeType::Whitelisted,
    );
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(
    state: &mut CompileState<'a, 'tcx>,
    validate: bool,
) {
    init_late_loggers();
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a> {
            tcx: TyCtxt<'a, 'tcx, 'tcx>,
            state: &'a CompileState<'a, 'tcx>,
            validate: bool,
        };
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::ItemKind::Fn(.., body_id) = i.node {
                    if i.attrs.iter().any(|attr| {
                        attr.name() == "test"
                    })
                    {
                        let did = self.tcx.hir.body_owner_def_id(body_id);
                        println!(
                            "running test: {}",
                            self.tcx.def_path_debug_str(did),
                        );
                        miri::eval_main(self.tcx, did, self.validate);
                        self.state.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(
            &mut Visitor { tcx, state, validate }
        );
    } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        miri::eval_main(tcx, entry_def_id, validate);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn init_early_loggers() {
    // Notice that our `extern crate log` is NOT the same as rustc's!  So we have to initialize
    // them both.  We always initialize miri early.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize rustc if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and NOT log anything for what happens before
    // miri gets started.
    if env::var("RUST_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // Initializing loggers right before we start evaluation.  We overwrite the RUST_LOG
    // env var if it is not set, control it based on MIRI_LOG.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUST_LOG").is_err() {
            // We try to be a bit clever here: If MIRI_LOG is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related.  Only if MIRI_LOG contains `module=level`, we just
            // use the same value for RUST_LOG.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if var.contains('=') {
                env::set_var("RUST_LOG", &var);
            } else {
                env::set_var("RUST_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            }
            rustc_driver::init_rustc_env_logger();
        }
    }
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "Could not find sysroot. Either set MIRI_SYSROOT at run-time, or at \
                     build-time specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

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

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    let mut validate = true;
    args.retain(|arg| {
        match arg.as_str() {
            "-Zmiri-disable-validation" => {
                validate = false;
                false
            },
            _ => true
        }
    });

    let result = rustc_driver::run(move || {
        rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
            default: Box::new(RustcDefaultCalls),
            validate,
        }), None, None)
    });
    std::process::exit(result as i32);
}
<|endoftext|>


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

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct LLA {
    pub lat_deg: f64,
    pub lon_deg: f64,
    pub alt_m:   f64,
}

impl PartialEq for LLA {
    fn eq(&self, other: &LLA) -> bool {
        (self.alt_m   - other.alt_m).abs()   < 0.000_000_1 &&
        (self.lat_deg - other.lat_deg).abs() < 0.000_000_1 &&
        (self.lon_deg - other.lon_deg).abs() < 0.000_000_1
    }
}

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct ECEF {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl PartialEq for ECEF {
    fn eq(&self, other: &ECEF) -> bool {
        (self.x - other.x).abs() < 0.000_000_1 &&
        (self.y - other.y).abs() < 0.000_000_1 &&
        (self.z - other.z).abs() < 0.000_000_1
    }
}
<commit_msg>impl From traits between LLA and ECEF<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use std::convert::From;
use ::conversions::{ecef_to_lla, lla_to_ecef};

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct LLA {
    pub lat_deg: f64,
    pub lon_deg: f64,
    pub alt_m:   f64,
}

impl PartialEq for LLA {
    fn eq(&self, other: &LLA) -> bool {
        (self.alt_m   - other.alt_m).abs()   < 0.000_000_1 &&
        (self.lat_deg - other.lat_deg).abs() < 0.000_000_1 &&
        (self.lon_deg - other.lon_deg).abs() < 0.000_000_1
    }
}

impl From<ECEF> for LLA {
    fn from(ecef: ECEF) -> LLA {
        ecef_to_lla(&ecef)
    }
}

impl<'a> From<&'a ECEF> for LLA {
    fn from(ecef: &ECEF) -> LLA {
        ecef_to_lla(ecef)
    }
}

impl<'a> From<&'a LLA> for LLA {
    fn from(lla: &LLA) -> LLA {
        (*lla).clone()
    }
}

#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct ECEF {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl PartialEq for ECEF {
    fn eq(&self, other: &ECEF) -> bool {
        (self.x - other.x).abs() < 0.000_000_1 &&
        (self.y - other.y).abs() < 0.000_000_1 &&
        (self.z - other.z).abs() < 0.000_000_1
    }
}

impl From<LLA> for ECEF {
    fn from(lla: LLA) -> ECEF {
        lla_to_ecef(&lla)
    }
}

impl<'a> From<&'a LLA> for ECEF {
    fn from(lla: &LLA) -> ECEF {
        lla_to_ecef(lla)
    }
}

impl<'a> From<&'a ECEF> for ECEF {
    fn from(ecef: &ECEF) -> ECEF {
        (*ecef).clone()
    }
}
<|endoftext|>


<commit_before>use error;
use self::MultiHashVariant::*;

#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[allow(non_camel_case_types)]
/// The possible multihash variants.
pub enum MultiHashVariant {
    /// A straight copy of the data supposedly hashed.
    /// May be a prefix rather than a full copy.
    Identity,

    /// A 160-bit [SHA-1][] digest + length.
    /// [SHA-1]: https://en.wikipedia.org/wiki/SHA-1
    Sha1,

    /// A 256-bit [SHA-2][] digest + length.
    /// [SHA-2]: https://en.wikipedia.org/wiki/SHA-2
    Sha2_256,

    /// A 512-bit [SHA-2][] digest + length.
    /// [SHA-2]: https://en.wikipedia.org/wiki/SHA-2
    Sha2_512,

    /// A 512-bit [SHA-3][] digest + length.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_512,

    /// A 384-bit [SHA-3][] digest + length.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_384,

    /// A 256-bit [SHA-3][] digest + length.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_256,

    /// A 224-bit [SHA-3][] digest + length.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_224,

    /// A variable size [SHAKE-128][] digest.
    /// [SHAKE-128]: https://en.wikipedia.org/wiki/SHA-3
    Shake128,

    /// A variable size [SHAKE-256][] digest.
    /// [SHAKE-256]: https://en.wikipedia.org/wiki/SHA-3
    Shake256,

    /// A 512-bit [BLAKE2b][] digest.
    /// [BLAKE2b]: https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2
    Blake2B,

    /// A 256-bit [BLAKE2s][] digest.
    /// [BLAKE2s]: https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2
    Blake2S,

    /// An application specific MultiHash variant.
    ApplicationSpecific {
        /// The application specific code for this variant, must be in the
        /// range [0x0400, 0x040f].
        code: usize
    },

    #[doc(hidden)]
    /// Ensure extending this enum is a non-breaking change, unless users
    /// really want to break it...
    __Nonexhaustive,
}

impl MultiHashVariant {
    /// Returns the multihash variant that the given code refers to, validates
    /// that the code is known or an application specific variant.
    pub fn from_code(code: usize) -> error::creation::Result<MultiHashVariant> {
        Ok(match code {
            0x00 => Identity,
            0x11 => Sha1,
            0x12 => Sha2_256,
            0x13 => Sha2_512,
            0x14 => Sha3_512,
            0x15 => Sha3_384,
            0x16 => Sha3_256,
            0x17 => Sha3_224,
            0x18 => Shake128,
            0x19 => Shake256,

            0x40 => Blake2B,
            0x41 => Blake2S,

            0x0400 ... 0x040f => ApplicationSpecific { code: code },
            _ => {
                return Err(error::creation::ErrorKind::UnknownCode(code).into());
            }
        })
    }

    /// Returns the multihash variant that the given code refers to, validates
    /// that the code is known or an application specific variant, and that the
    /// length is consistent with the multihash variant the code refers to.
    pub fn from_code_and_length(code: usize, length: usize) -> error::creation::Result<MultiHashVariant> {
        let variant = try!(MultiHashVariant::from_code(code));
        try!(variant.check_length(length));
        Ok(variant)
    }

    /// Validates that the length is consistent with this multihash variant.
    pub fn check_length(self, length: usize) -> error::creation::Result<()> {
        if length > self.max_len() {
            Err(error::creation::ErrorKind::LengthTooLong(self, length).into())
        } else {
            Ok(())
        }
    }

    /// The maximum digest length allowed for this multihash variant.
    pub fn max_len(self) -> usize {
        match self {
            Sha1 => 20,
            Sha3_224 => 28,
            Sha2_256 | Sha3_256 | Blake2S => 32,
            Sha3_384 => 48,
            Sha2_512 | Sha3_512 | Blake2B => 64,
            Identity | Shake128 | Shake256 | ApplicationSpecific { .. }
                => usize::max_value(),
            __Nonexhaustive => unreachable!(),
        }
    }

    /// The code specifying this multihash variant.
    pub fn code(self) -> usize {
        match self {
            Identity => 0x00,
            Sha1 => 0x11,
            Sha2_256 => 0x12,
            Sha2_512 => 0x13,
            Sha3_512 => 0x14,
            Sha3_384 => 0x15,
            Sha3_256 => 0x16,
            Sha3_224 => 0x17,
            Shake128 => 0x18,
            Shake256 => 0x19,
            Blake2B => 0x40,
            Blake2S => 0x41,
            ApplicationSpecific { code } => {
                assert!(code > 0x0400 && code < 0x040f, "application specific code {:#04x} outside allowed range 0x0400-0x040f", code);
                code
            }
            __Nonexhaustive => unreachable!(),
        }
    }

    /// The string representation of this multihash type.
    pub fn name(self) -> &'static str {
        match self {
            Identity => "identity",
            Sha1 => "sha1",
            Sha2_256 => "sha2-256",
            Sha2_512 => "sha2-512",
            Sha3_224 => "sha3-224",
            Sha3_256 => "sha3-256",
            Sha3_384 => "sha3-384",
            Sha3_512 => "sha3-512",
            Shake128 => "shake-128",
            Shake256 => "shake-256",
            Blake2B => "blake2b",
            Blake2S => "blake2s",
            ApplicationSpecific { code } => {
                assert!(code > 0x0400 && code < 0x040f, "application specific code {:#04x} outside allowed range 0x0400-0x040f", code);
                "app-specific"
            }
            __Nonexhaustive => unreachable!(),
        }
    }

}

<commit_msg>Fix docs after refactor<commit_after>use error;
use self::MultiHashVariant::*;

#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[allow(non_camel_case_types)]
/// The possible multihash variants.
pub enum MultiHashVariant {
    /// A straight copy of the data supposedly hashed.
    /// May be a prefix rather than a full copy.
    Identity,

    /// A 160-bit [SHA-1][] digest.
    /// [SHA-1]: https://en.wikipedia.org/wiki/SHA-1
    Sha1,

    /// A 256-bit [SHA-2][] digest.
    /// [SHA-2]: https://en.wikipedia.org/wiki/SHA-2
    Sha2_256,

    /// A 512-bit [SHA-2][] digest.
    /// [SHA-2]: https://en.wikipedia.org/wiki/SHA-2
    Sha2_512,

    /// A 512-bit [SHA-3][] digest.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_512,

    /// A 384-bit [SHA-3][] digest.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_384,

    /// A 256-bit [SHA-3][] digest.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_256,

    /// A 224-bit [SHA-3][] digest.
    /// [SHA-3]: https://en.wikipedia.org/wiki/SHA-3
    Sha3_224,

    /// A variable size [SHAKE-128][] digest.
    /// [SHAKE-128]: https://en.wikipedia.org/wiki/SHA-3
    Shake128,

    /// A variable size [SHAKE-256][] digest.
    /// [SHAKE-256]: https://en.wikipedia.org/wiki/SHA-3
    Shake256,

    /// A 512-bit [BLAKE2b][] digest.
    /// [BLAKE2b]: https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2
    Blake2B,

    /// A 256-bit [BLAKE2s][] digest.
    /// [BLAKE2s]: https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2
    Blake2S,

    /// An application specific MultiHash variant.
    ApplicationSpecific {
        /// The application specific code for this variant, must be in the
        /// range [0x0400, 0x040f].
        code: usize
    },

    #[doc(hidden)]
    /// Ensure extending this enum is a non-breaking change, unless users
    /// really want to break it...
    __Nonexhaustive,
}

impl MultiHashVariant {
    /// Returns the multihash variant that the given code refers to, validates
    /// that the code is known or an application specific variant.
    pub fn from_code(code: usize) -> error::creation::Result<MultiHashVariant> {
        Ok(match code {
            0x00 => Identity,
            0x11 => Sha1,
            0x12 => Sha2_256,
            0x13 => Sha2_512,
            0x14 => Sha3_512,
            0x15 => Sha3_384,
            0x16 => Sha3_256,
            0x17 => Sha3_224,
            0x18 => Shake128,
            0x19 => Shake256,

            0x40 => Blake2B,
            0x41 => Blake2S,

            0x0400 ... 0x040f => ApplicationSpecific { code: code },
            _ => {
                return Err(error::creation::ErrorKind::UnknownCode(code).into());
            }
        })
    }

    /// Returns the multihash variant that the given code refers to, validates
    /// that the code is known or an application specific variant, and that the
    /// length is consistent with the multihash variant the code refers to.
    pub fn from_code_and_length(code: usize, length: usize) -> error::creation::Result<MultiHashVariant> {
        let variant = try!(MultiHashVariant::from_code(code));
        try!(variant.check_length(length));
        Ok(variant)
    }

    /// Validates that the length is consistent with this multihash variant.
    pub fn check_length(self, length: usize) -> error::creation::Result<()> {
        if length > self.max_len() {
            Err(error::creation::ErrorKind::LengthTooLong(self, length).into())
        } else {
            Ok(())
        }
    }

    /// The maximum digest length allowed for this multihash variant.
    pub fn max_len(self) -> usize {
        match self {
            Sha1 => 20,
            Sha3_224 => 28,
            Sha2_256 | Sha3_256 | Blake2S => 32,
            Sha3_384 => 48,
            Sha2_512 | Sha3_512 | Blake2B => 64,
            Identity | Shake128 | Shake256 | ApplicationSpecific { .. }
                => usize::max_value(),
            __Nonexhaustive => unreachable!(),
        }
    }

    /// The code specifying this multihash variant.
    pub fn code(self) -> usize {
        match self {
            Identity => 0x00,
            Sha1 => 0x11,
            Sha2_256 => 0x12,
            Sha2_512 => 0x13,
            Sha3_512 => 0x14,
            Sha3_384 => 0x15,
            Sha3_256 => 0x16,
            Sha3_224 => 0x17,
            Shake128 => 0x18,
            Shake256 => 0x19,
            Blake2B => 0x40,
            Blake2S => 0x41,
            ApplicationSpecific { code } => {
                assert!(code > 0x0400 && code < 0x040f, "application specific code {:#04x} outside allowed range 0x0400-0x040f", code);
                code
            }
            __Nonexhaustive => unreachable!(),
        }
    }

    /// The string representation of this multihash type.
    pub fn name(self) -> &'static str {
        match self {
            Identity => "identity",
            Sha1 => "sha1",
            Sha2_256 => "sha2-256",
            Sha2_512 => "sha2-512",
            Sha3_224 => "sha3-224",
            Sha3_256 => "sha3-256",
            Sha3_384 => "sha3-384",
            Sha3_512 => "sha3-512",
            Shake128 => "shake-128",
            Shake256 => "shake-256",
            Blake2B => "blake2b",
            Blake2S => "blake2s",
            ApplicationSpecific { code } => {
                assert!(code > 0x0400 && code < 0x040f, "application specific code {:#04x} outside allowed range 0x0400-0x040f", code);
                "app-specific"
            }
            __Nonexhaustive => unreachable!(),
        }
    }

}

<|endoftext|>


<commit_before>use std::collections::HashMap;

use analysis::types::IsIncomplete;
use library::*;
use nameutil;
use parser::is_empty_c_type;
use traits::MaybeRefAs;
use config::Config;
use config::gobjects::GObject;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self, config: &Config) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
        self.correlate_class_structs();
        self.fix_fields();
        self.make_unrepresentable_types_opaque();
        self.mark_final_types(config);
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_
            .get_glib_name()
            .map(|glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            })
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Record(ref record) = *type_ {
                    if let Some(ref struct_for) = record.gtype_struct_for {
                        if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                            structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                        }
                    }
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }

    fn correlate_class_structs(&self) {
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let name;
                let type_struct;
                let c_class_type;

                match *type_ {
                    Type::Class(ref klass) => {
                        name         = &klass.name;
                        type_struct  = &klass.type_struct;
                        c_class_type = &klass.c_class_type;
                    },

                    Type::Interface(ref iface) => {
                        name         = &iface.name;
                        type_struct  = &iface.type_struct;
                        c_class_type = &iface.c_class_type;
                    },

                    _ => { continue; }
                }

                if let Some(ref type_struct) = *type_struct {
                    let type_struct_tid = self.find_type(ns_id as u16, type_struct);
                    if type_struct_tid.is_none() {
                        panic!("\"{}\" has glib:type-struct=\"{}\" but there is no such record",
                               name,
                               type_struct);
                    }

                    let type_struct_type = self.type_(type_struct_tid.unwrap());

                    if let Type::Record(ref r) = *type_struct_type {
                        if r.gtype_struct_for.as_ref() != Some(name) {
                            if let Some(ref gtype_struct_for) = r.gtype_struct_for {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
                                       name,
                                       type_struct,
                                       r.name,
                                       gtype_struct_for);
                            } else {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
                                       name,
                                       type_struct,
                                       r.name);
                            }
                        }
                    } else {
                        panic!("Element with name=\"{}\" should be a record but it isn't",
                               type_struct);
                    }
                } else if let Some(ref c) = *c_class_type {
                    panic!("\"{}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{}\"",
                           name,
                           c);
                }
                // else both type_struct and c_class_type are None,
                // and that's fine because they don't reference each
                // other.
            }
        }
    }

    fn fix_fields(&mut self) {
        enum Action {
            SetCType(String),
            SetName(String),
        }
        let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class { ref name, ref fields, ..}) |
                    Type::Record(Record { ref name, ref fields, ..}) |
                    Type::Union(Union { ref name, ref fields, ..}) => {
                        for (fid, field) in fields.iter().enumerate() {
                            if nameutil::needs_mangling(&field.name) {
                                let new_name = nameutil::mangle_keywords(&*field.name).into_owned();
                                actions.push((tid, fid, Action::SetName(new_name)));
                            }
                            if field.c_type.is_some() {
                                continue;
                            }
                            let field_type = self.type_(field.typ);
                            if field_type.maybe_ref_as::<Function>().is_some() {
                                // Function pointers generally don't have c_type.
                                continue;
                            }
                            if let Some(c_type) = field_type.get_glib_name() {
                                actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
                                continue;
                            }
                            if let Type::Fundamental(Fundamental::Pointer) = *field_type {
                                // For example SoupBuffer is missing c:type for data field.
                                actions.push((tid, fid, Action::SetCType("void*".to_owned())));
                                continue;
                            }
                            error!("Field `{}::{}` is missing c:type", name, &field.name);
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, fid, action) in actions {
            match *self.type_mut(tid) {
                Type::Class(Class { ref name, ref mut fields, ..}) |
                Type::Record(Record { ref name, ref mut fields, ..}) |
                Type::Union(Union { ref name, ref mut fields, ..}) => {
                    match action {
                        Action::SetCType(c_type) => {
                            warn_main!(tid, "Field `{}::{}` missing c:type assumed to be `{}`",
                                  name, &fields[fid].name, c_type);
                            fields[fid].c_type = Some(c_type);
                        }
                        Action::SetName(name) => fields[fid].name = name,
                    }
                },
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }

    fn make_unrepresentable_types_opaque(&mut self) {
        // Unions with non-`Copy` fields are unstable (see issue #32836).
        // It would seem that this shouldn't be cause for concern as one can
        // always make all types in the union copyable.
        //
        // Unfortunately, this is not that simple, as some types are currently
        // unrepresentable in Rust, and they do occur inside the unions.
        // Thus to avoid the problem, we mark all unions with such unrepresentable
        // types as opaque, and don't generate their definitions.
        let mut unrepresentable: Vec<TypeId> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap();
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Union(Union {ref fields, ..}) if fields.as_slice().is_incomplete(self) =>
                        unrepresentable.push(tid),
                    _ => {},
                }
            }
        }
        for tid in unrepresentable {
            match *self.type_mut(tid) {
                Type::Union(Union {ref name, ref mut fields, ..}) => {
                    info!("Type `{}` is not representable.", name);
                    fields.clear();
                }
                _ => unreachable!("Expected a union"),
            }
        }
    }

    fn has_subtypes(&self, parent_tid: TypeId) -> bool {
        for (tid, _) in self.types() {
            if let Type::Class(ref class) = *self.type_(tid) {
                if class.parent == Some(parent_tid) {
                    return true;
                }
            }
        }

        false
    }

    fn mark_final_types(&mut self, config: &Config) {
        // Here we mark all class types as final types if configured so in the config or
        // otherwise if there is no public class struct for the type and there are no
        // known subtypes.
        //
        // Final types can't have any subclasses and we handle them slightly different
        // for that reason.
        // FIXME: without class_hierarchy this function O(n2) due inner loop in `has_subtypes`
        let mut final_types: Vec<TypeId> = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Class(ref klass) = *type_ {
                    let tid = TypeId {
                        ns_id: ns_id as u16,
                        id: id as u32,
                    };

                    let full_name = tid.full_name(self);
                    let obj = config.objects.get(&*full_name);

                    if let Some(GObject { final_type: Some(final_type), ..}) = obj {
                        // The config might also be used to override a type that is wrongly
                        // detected as final type otherwise
                        if *final_type {
                            final_types.push(tid);
                        }
                    } else if klass.c_class_type.is_none() && !self.has_subtypes(tid) {
                        final_types.push(tid);
                    }
                }
            }
        }

        for tid in final_types {
            if let Type::Class(Class { ref mut final_type, ..}) = *self.type_mut(tid) {
                *final_type = true;
            } else {
                unreachable!();
            }
        }
    }
}
<commit_msg>library_postprocessing: Don't expect c:type for FixedArray<commit_after>use std::collections::HashMap;

use analysis::types::IsIncomplete;
use library::*;
use nameutil;
use parser::is_empty_c_type;
use traits::MaybeRefAs;
use config::Config;
use config::gobjects::GObject;

impl Namespace {
    fn unresolved(&self) -> Vec<&str> {
        self.index
            .iter()
            .filter_map(|(name, &id)| if self.types[id as usize].is_none() {
                Some(&name[..])
            } else {
                None
            })
            .collect()
    }
}

type DetectedCTypes = HashMap<TypeId, String>;

impl Library {
    pub fn postprocessing(&mut self, config: &Config) {
        self.fix_gtype();
        self.check_resolved();
        self.fill_empty_signals_c_types();
        self.resolve_class_structs();
        self.correlate_class_structs();
        self.fix_fields();
        self.make_unrepresentable_types_opaque();
        self.mark_final_types(config);
    }

    fn fix_gtype(&mut self) {
        if let Some(ns_id) = self.find_namespace("GObject") {
            // hide the `GType` type alias in `GObject`
            self.add_type(ns_id, "Type", Type::Fundamental(Fundamental::Unsupported));
        }
    }

    fn check_resolved(&self) {
        let list: Vec<_> = self.index
            .iter()
            .flat_map(|(name, &id)| {
                let name = name.clone();
                self.namespace(id)
                    .unresolved()
                    .into_iter()
                    .map(move |s| format!("{}.{}", name, s))
            })
            .collect();

        if !list.is_empty() {
            panic!("Incomplete library, unresolved: {:?}", list);
        }
    }

    fn fill_empty_signals_c_types(&mut self) {
        let mut tids = Vec::new();
        let mut c_types = DetectedCTypes::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(ref klass) => {
                        if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    Type::Interface(ref iface) => {
                        if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
                            tids.push(tid);
                        }
                    }
                    _ => (),
                }
            }
        }

        fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
            for signal in signals {
                update_empty_signal_c_types(signal, c_types);
            }
        }

        fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
            for par in &mut signal.parameters {
                update_empty_c_type(&mut par.c_type, par.typ, c_types);
            }
            update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
        }

        fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
            if !is_empty_c_type(c_type) {
                return;
            }
            if let Some(ref mut s) = c_types.get(&tid) {
                *c_type = s.clone();
            }
        }

        for tid in tids {
            match *self.type_mut(tid) {
                Type::Class(ref mut klass) => {
                    update_empty_signals_c_types(&mut klass.signals, &c_types)
                }
                Type::Interface(ref mut iface) => {
                    update_empty_signals_c_types(&mut iface.signals, &c_types)
                }
                _ => (),
            }
        }
    }

    fn detect_empty_signals_c_types(
        &self,
        signals: &[Signal],
        c_types: &mut DetectedCTypes,
    ) -> bool {
        let mut detected = false;
        for signal in signals {
            if self.detect_empty_signal_c_types(signal, c_types) {
                detected = true;
            }
        }
        detected
    }

    fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
        let mut detected = false;
        for par in &signal.parameters {
            if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
                detected = true;
            }
        }
        if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
            detected = true;
        }
        detected
    }

    fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
        if !is_empty_c_type(c_type) {
            return false;
        }
        if !c_types.contains_key(&tid) {
            if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
                c_types.insert(tid, detected_c_type);
            }
        }
        true
    }

    fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
        let type_ = self.type_(tid);
        type_
            .get_glib_name()
            .map(|glib_name| if self.is_referenced_type(type_) {
                format!("{}*", glib_name)
            } else {
                glib_name.to_string()
            })
    }

    fn is_referenced_type(&self, type_: &Type) -> bool {
        use library::Type::*;
        match *type_ {
            Alias(ref alias) => self.is_referenced_type(self.type_(alias.typ)),
            Record(..) | Union(..) | Class(..) | Interface(..) => true,
            _ => false,
        }
    }

    fn resolve_class_structs(&mut self) {
        // stores pairs of (gtype-struct-c-name, type-name)
        let mut structs_and_types = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Record(ref record) = *type_ {
                    if let Some(ref struct_for) = record.gtype_struct_for {
                        if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
                            structs_and_types.push ((record.c_type.clone(), struct_for_tid));
                        }
                    }
                }
            }
        }

        for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
            match *self.type_mut(struct_for_tid) {
                Type::Class(ref mut klass) => {
                    klass.c_class_type = Some(gtype_struct_c_type);
                },

                Type::Interface(ref mut iface) => {
                    iface.c_class_type = Some(gtype_struct_c_type);
                },

                ref x => unreachable!("Something other than a class or interface has a class struct: {:?}", x)
            }
        }
    }

    fn correlate_class_structs(&self) {
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for type_ in &ns.types {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let name;
                let type_struct;
                let c_class_type;

                match *type_ {
                    Type::Class(ref klass) => {
                        name         = &klass.name;
                        type_struct  = &klass.type_struct;
                        c_class_type = &klass.c_class_type;
                    },

                    Type::Interface(ref iface) => {
                        name         = &iface.name;
                        type_struct  = &iface.type_struct;
                        c_class_type = &iface.c_class_type;
                    },

                    _ => { continue; }
                }

                if let Some(ref type_struct) = *type_struct {
                    let type_struct_tid = self.find_type(ns_id as u16, type_struct);
                    if type_struct_tid.is_none() {
                        panic!("\"{}\" has glib:type-struct=\"{}\" but there is no such record",
                               name,
                               type_struct);
                    }

                    let type_struct_type = self.type_(type_struct_tid.unwrap());

                    if let Type::Record(ref r) = *type_struct_type {
                        if r.gtype_struct_for.as_ref() != Some(name) {
                            if let Some(ref gtype_struct_for) = r.gtype_struct_for {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
                                       name,
                                       type_struct,
                                       r.name,
                                       gtype_struct_for);
                            } else {
                                panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
                                       name,
                                       type_struct,
                                       r.name);
                            }
                        }
                    } else {
                        panic!("Element with name=\"{}\" should be a record but it isn't",
                               type_struct);
                    }
                } else if let Some(ref c) = *c_class_type {
                    panic!("\"{}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{}\"",
                           name,
                           c);
                }
                // else both type_struct and c_class_type are None,
                // and that's fine because they don't reference each
                // other.
            }
        }
    }

    fn fix_fields(&mut self) {
        enum Action {
            SetCType(String),
            SetName(String),
        }
        let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Class(Class { ref name, ref fields, ..}) |
                    Type::Record(Record { ref name, ref fields, ..}) |
                    Type::Union(Union { ref name, ref fields, ..}) => {
                        for (fid, field) in fields.iter().enumerate() {
                            if nameutil::needs_mangling(&field.name) {
                                let new_name = nameutil::mangle_keywords(&*field.name).into_owned();
                                actions.push((tid, fid, Action::SetName(new_name)));
                            }
                            if field.c_type.is_some() {
                                continue;
                            }
                            let field_type = self.type_(field.typ);
                            if field_type.maybe_ref_as::<Function>().is_some() {
                                // Function pointers generally don't have c_type.
                                continue;
                            }
                            if let Some(c_type) = field_type.get_glib_name() {
                                actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
                                continue;
                            }
                            if let Type::Fundamental(Fundamental::Pointer) = *field_type {
                                // For example SoupBuffer is missing c:type for data field.
                                actions.push((tid, fid, Action::SetCType("void*".to_owned())));
                                continue;
                            }
                            if let Type::FixedArray(_, _, Some(ref c_type)) = *field_type {
                                // fixed-size Arrays can only have inner c_type
                                actions.push((tid, fid, Action::SetCType(c_type.clone())));
                                continue;
                            }
                            error!("Field `{}::{}` is missing c:type", name, &field.name);
                        }
                    },
                    _ => {},
                }
            }
        }
        for (tid, fid, action) in actions {
            match *self.type_mut(tid) {
                Type::Class(Class { ref name, ref mut fields, ..}) |
                Type::Record(Record { ref name, ref mut fields, ..}) |
                Type::Union(Union { ref name, ref mut fields, ..}) => {
                    match action {
                        Action::SetCType(c_type) => {
                            warn_main!(tid, "Field `{}::{}` missing c:type assumed to be `{}`",
                                  name, &fields[fid].name, c_type);
                            fields[fid].c_type = Some(c_type);
                        }
                        Action::SetName(name) => fields[fid].name = name,
                    }
                },
                _ => unreachable!("Expected class, record or union"),
            }
        }
    }

    fn make_unrepresentable_types_opaque(&mut self) {
        // Unions with non-`Copy` fields are unstable (see issue #32836).
        // It would seem that this shouldn't be cause for concern as one can
        // always make all types in the union copyable.
        //
        // Unfortunately, this is not that simple, as some types are currently
        // unrepresentable in Rust, and they do occur inside the unions.
        // Thus to avoid the problem, we mark all unions with such unrepresentable
        // types as opaque, and don't generate their definitions.
        let mut unrepresentable: Vec<TypeId> = Vec::new();
        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap();
                let tid = TypeId {
                    ns_id: ns_id as u16,
                    id: id as u32,
                };
                match *type_ {
                    Type::Union(Union {ref fields, ..}) if fields.as_slice().is_incomplete(self) =>
                        unrepresentable.push(tid),
                    _ => {},
                }
            }
        }
        for tid in unrepresentable {
            match *self.type_mut(tid) {
                Type::Union(Union {ref name, ref mut fields, ..}) => {
                    info!("Type `{}` is not representable.", name);
                    fields.clear();
                }
                _ => unreachable!("Expected a union"),
            }
        }
    }

    fn has_subtypes(&self, parent_tid: TypeId) -> bool {
        for (tid, _) in self.types() {
            if let Type::Class(ref class) = *self.type_(tid) {
                if class.parent == Some(parent_tid) {
                    return true;
                }
            }
        }

        false
    }

    fn mark_final_types(&mut self, config: &Config) {
        // Here we mark all class types as final types if configured so in the config or
        // otherwise if there is no public class struct for the type and there are no
        // known subtypes.
        //
        // Final types can't have any subclasses and we handle them slightly different
        // for that reason.
        // FIXME: without class_hierarchy this function O(n2) due inner loop in `has_subtypes`
        let mut final_types: Vec<TypeId> = Vec::new();

        for (ns_id, ns) in self.namespaces.iter().enumerate() {
            for (id, type_) in ns.types.iter().enumerate() {
                let type_ = type_.as_ref().unwrap(); //Always contains something

                if let Type::Class(ref klass) = *type_ {
                    let tid = TypeId {
                        ns_id: ns_id as u16,
                        id: id as u32,
                    };

                    let full_name = tid.full_name(self);
                    let obj = config.objects.get(&*full_name);

                    if let Some(GObject { final_type: Some(final_type), ..}) = obj {
                        // The config might also be used to override a type that is wrongly
                        // detected as final type otherwise
                        if *final_type {
                            final_types.push(tid);
                        }
                    } else if klass.c_class_type.is_none() && !self.has_subtypes(tid) {
                        final_types.push(tid);
                    }
                }
            }
        }

        for tid in final_types {
            if let Type::Class(Class { ref mut final_type, ..}) = *self.type_mut(tid) {
                *final_type = true;
            } else {
                unreachable!();
            }
        }
    }
}
<|endoftext|>