<commit_before>use token::Token;
use error::Result;

use std::str::CharIndices;
use std::iter::Peekable;

pub struct Tokenizer<'a> {
    text: &'a str,
    chars: Peekable<CharIndices<'a>>,
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Result<Token>;

    fn next(&mut self) -> Option<Result<Token>> {
        match self.parse() {
            Ok(Some(t)) => Some(Ok(t)),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

impl<'a> Tokenizer<'a> {
    pub fn new(text: &str) -> Tokenizer {
        Tokenizer {
            text: text,
            chars: text.char_indices().peekable(),
        }
    }

    pub fn parse(&mut self) -> Result<Option<Token>> {
        let mut value = String::new();
        let mut start;
        while let Some((char_offset, curr_char)) = self.chars.next() {
            // Skip leading whitespace
            if curr_char.is_whitespace() {
                continue;
            } else {
                if is_single_char_token(curr_char) {
                    return Ok(Some(Token {
                        value: curr_char.to_string(),
                        offset: Some(char_offset),
                    }))
                } else {
                    // Start of a multi-char token
                    // First non-whitespace - save its offset to be the Token's offset
                    value.push(curr_char);
                    start = char_offset;
                    while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                        // Stop when we reach a non-word char
                        if next_char.is_whitespace() || is_single_char_token(next_char) {
                            break;
                        } else {
                            value.push(next_char);
                            self.chars.next();
                        }
                    }
                    return Ok(Some(Token { value: value, offset: Some(start) }))
                }
            }
        }
        return Ok(None)
    }
}

fn is_single_char_token(ch: char) -> bool {
    "{}:;".chars().any(|c| c == ch)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut tokenizer = Tokenizer::new("");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_none_for_only_whitespace() {
        let mut tokenizer = Tokenizer::new("     ");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_words() {
        // Without regard to Sass word validity
        let mut tokenizer = Tokenizer::new(" \n  div   aoeu  ");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("div", 4))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("aoeu", 10))));
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_curly_braces() {
        // Without regard to matching
        let mut tokenizer = Tokenizer::new("{}}a{ blue}");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("{", 0))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("}", 1))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("}", 2))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("a", 3))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("{", 4))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("blue", 6))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("}", 10))));
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_colon() {
        let mut tokenizer = Tokenizer::new(":invalid: property::");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 0))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("invalid", 1))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 8))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("property", 10))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 18))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 19))));
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_semicolon() {
        let mut tokenizer = Tokenizer::new(";;\na;\nb\n;");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 0))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 1))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("a", 2))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 3))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("b", 4))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 5))));
        assert_eq!(tokenizer.next(), None);
    }
}
<commit_msg>Handle integers and floats<commit_after>use token::Token;
use error::Result;

use std::str::CharIndices;
use std::iter::Peekable;

pub struct Tokenizer<'a> {
    text: &'a str,
    chars: Peekable<CharIndices<'a>>,
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Result<Token>;

    fn next(&mut self) -> Option<Result<Token>> {
        match self.parse() {
            Ok(Some(t)) => Some(Ok(t)),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

impl<'a> Tokenizer<'a> {
    pub fn new(text: &str) -> Tokenizer {
        Tokenizer {
            text: text,
            chars: text.char_indices().peekable(),
        }
    }

    pub fn parse(&mut self) -> Result<Option<Token>> {
        let mut value = String::new();
        let mut start;
        while let Some((char_offset, curr_char)) = self.chars.next() {
            // Skip leading whitespace
            if curr_char.is_whitespace() {
                continue;
            } else {
                if is_single_char_token(curr_char) {
                    return Ok(Some(Token {
                        value: curr_char.to_string(),
                        offset: Some(char_offset),
                    }))
                } else if curr_char.is_numeric() {
                    // Start of a multi-char numeric token
                    value.push(curr_char);
                    start = char_offset;

                    while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                        // Stop when we reach a non-numeric char
                        if !next_char.is_numeric() && next_char != '.' {
                            break;
                        } else {
                            value.push(next_char);
                            self.chars.next();
                        }
                    }
                    return Ok(Some(Token { value: value, offset: Some(start) }))
                } else {
                    // Start of a multi-char non-numeric token
                    // First non-whitespace - save its offset to be the Token's offset
                    value.push(curr_char);
                    start = char_offset;
                    while let Some(&(next_char_offset, next_char)) = self.chars.peek() {
                        // Stop when we reach a non-word char
                        if next_char.is_whitespace() || is_single_char_token(next_char) {
                            break;
                        } else {
                            value.push(next_char);
                            self.chars.next();
                        }
                    }
                    return Ok(Some(Token { value: value, offset: Some(start) }))
                }
            }
        }
        return Ok(None)
    }
}

fn is_single_char_token(ch: char) -> bool {
    "{}:;".chars().any(|c| c == ch)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token;

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut tokenizer = Tokenizer::new("");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_none_for_only_whitespace() {
        let mut tokenizer = Tokenizer::new("     ");
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_returns_words() {
        // Without regard to Sass word validity
        let mut tokenizer = Tokenizer::new(" \n  div   aoeu  ");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("div", 4))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("aoeu", 10))));
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_curly_braces() {
        // Without regard to matching
        let mut tokenizer = Tokenizer::new("{}}a{ blue}");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("{", 0))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("}", 1))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("}", 2))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("a", 3))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("{", 4))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("blue", 6))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("}", 10))));
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_colon() {
        let mut tokenizer = Tokenizer::new(":invalid: property::");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 0))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("invalid", 1))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 8))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("property", 10))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 18))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 19))));
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_semicolon() {
        let mut tokenizer = Tokenizer::new(";;\na;\nb\n;");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 0))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 1))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("a", 2))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 3))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("b", 4))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 5))));
        assert_eq!(tokenizer.next(), None);
    }

    #[test]
    fn it_separates_numbers() {
        let mut tokenizer = Tokenizer::new("border: 0px 1.5 11em;");
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("border", 0))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(":", 6))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("0", 7))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("px", 8))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("1.5", 11))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("11", 15))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new("em", 17))));
        assert_eq!(tokenizer.next(), Some(Ok(Token::new(";", 19))));
        assert_eq!(tokenizer.next(), None);
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::os::unix::prelude::AsRawFd;
use std::slice;
use std::ops;
use std::fs::File;
use std::marker::PhantomData;

use mmap;

pub struct TypedMemoryMap<T:Copy> {
    map:    mmap::MemoryMap,    // mapped file
    len:    usize,              // in bytes (needed because map extends to full block)
    phn:    PhantomData<T>,
}

impl<T:Copy> TypedMemoryMap<T> {
    pub fn new(filename: String) -> TypedMemoryMap<T> {
        let file = File::open(filename).unwrap();
        let size = file.metadata().unwrap().len() as usize;
        TypedMemoryMap {
            map: mmap::MemoryMap::new(size, &[mmap::MapOption::MapReadable,
                                              mmap::MapOption::MapFd(file.as_raw_fd())]).unwrap(),
            len: size / mem::size_of::<T>(),
            phn: PhantomData,
        }
    }
}

impl<T:Copy> ops::Index<ops::RangeFull> for TypedMemoryMap<T> {
    type Output = [T];
    #[inline]
    fn index(&self, _index: ops::RangeFull) -> &[T] {
        unsafe { slice::from_raw_parts(self.map.data() as *const T, self.len) }
    }
}
<commit_msg>better error information<commit_after>use std::mem;
use std::os::unix::prelude::AsRawFd;
use std::slice;
use std::ops;
use std::fs::File;
use std::marker::PhantomData;

use mmap;

pub struct TypedMemoryMap<T:Copy> {
    map:    mmap::MemoryMap,    // mapped file
    len:    usize,              // in bytes (needed because map extends to full block)
    phn:    PhantomData<T>,
}

impl<T:Copy> TypedMemoryMap<T> {
    pub fn new(filename: String) -> TypedMemoryMap<T> {
        let file = File::open(filename).ok().expect("error opening file");
        let size = file.metadata().ok().expect("error reading metadata").len() as usize;
        TypedMemoryMap {
            map: mmap::MemoryMap::new(size, &[mmap::MapOption::MapReadable,
                                              mmap::MapOption::MapFd(file.as_raw_fd())]).ok().expect("error mapping memory"),
            len: size / mem::size_of::<T>(),
            phn: PhantomData,
        }
    }
}

impl<T:Copy> ops::Index<ops::RangeFull> for TypedMemoryMap<T> {
    type Output = [T];
    #[inline]
    fn index(&self, _index: ops::RangeFull) -> &[T] {
        unsafe { slice::from_raw_parts(self.map.data() as *const T, self.len) }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "unsafe_ls"]
#![allow(unstable)]
extern crate arena;
extern crate getopts;
extern crate syntax;
extern crate rustc;
extern crate rustc_back;
extern crate rustc_driver;
extern crate rustc_trans;
extern crate rustc_typeck;

use rustc::session::{self, config};
use rustc_driver::driver;
use rustc::middle::ty;
use rustc::session::search_paths::SearchPaths;
use syntax::codemap::Pos;
use std::collections::{HashSet, HashMap};
use std::os;
use std::sync::Arc;
use std::thread::Thread;

mod visitor;

static DEFAULT_LIB_DIR: &'static str = "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib";

fn main() {
    let args: Vec<_> = std::os::args();
    let opts = [getopts::optflag("h", "help", "show this help message"),
                getopts::optflag("n", "nonffi",
                                 "print `unsafe`s that include non-FFI unsafe behaviours"),
                getopts::optflag("f", "ffi", "print `unsafe`s that do FFI calls"),
                getopts::optmulti("L", "library-path",
                                  "directories to add to crate search path", "DIR")];

    let matches = getopts::getopts(args.tail(), &opts).unwrap();
    if matches.opt_present("help") {
        println!("{}",
                 getopts::usage(format!("{} - find all unsafe blocks and print the \
                                unsafe actions within them", args[0]).as_slice(),
                     &opts));
        return;
    }

    let nonffi = matches.opt_present("nonffi");
    let ffi = matches.opt_present("ffi");
    let mut search_paths = SearchPaths::new();
    for path in matches.opt_strs("L").into_iter() {
        search_paths.add_path(&*path)
    }
    search_paths.add_path(DEFAULT_LIB_DIR);
    let externs = HashMap::new();

    let session = Arc::new(Session {
        nonffi: nonffi,
        ffi: ffi,
        externs: externs,
        search_paths: search_paths,
    });

    for name in matches.free.iter() {
        let sess = session.clone();
        let name = Path::new(name.as_slice());
        let _ = Thread::scoped(move || {
            sess.run_library(name);
        }).join();
    }
}

struct Session {
    nonffi: bool,
    ffi: bool,
    externs: Externs,
    search_paths: SearchPaths,
}

impl Session {
    fn run_library(&self, path: Path) {
        get_ast(path, self.search_paths.clone(), self.externs.clone(), |tcx| {
            let cm = tcx.sess.codemap();

            let mut visitor = visitor::UnsafeVisitor::new(tcx);
            visitor.check_crate(tcx.map.krate());

            for (_, info) in visitor.unsafes.iter() {
                // compiler generated block, so we don't care.
                if info.compiler { continue }

                let n = info.raw_deref.len()
                    + info.static_mut.len()
                    + info.unsafe_call.len()
                    + info.asm.len()
                    + info.transmute.len()
                    + info.transmute_imm_to_mut.len()
                    + info.cast_raw_ptr_const_to_mut.len();

                let f = info.ffi.len();

                if (self.nonffi && n > 0) || (self.ffi && f > 0) {
                    use syntax::codemap::Pos;

                    let mut v = Vec::new();
                    if self.nonffi {
                        for vv in [&info.raw_deref, &info.static_mut,
                                   &info.unsafe_call, &info.asm,
                                   &info.transmute,
                                   &info.transmute_imm_to_mut,
                                   &info.cast_raw_ptr_const_to_mut].iter() {
                            for s in vv.as_slice().iter() {
                                v.push(*s)
                            }
                        }
                    }
                    if self.ffi {
                        for s in info.ffi.as_slice().iter() {
                            v.push(*s)
                        }
                    }

                    let lo = cm.lookup_char_pos_adj(info.span.lo);

                    // print the summary line
                    println!("{}:{}:{}: {} with {:?}",
                             lo.filename,
                             lo.line, lo.col.to_usize() + 1,
                             if info.is_fn {"fn"} else {"block"},
                             *info);

                    // and the individual unsafe actions within each block
                    // (in source order)
                    v.as_mut_slice().sort_by(|a, b| a.lo.to_usize().cmp(&b.lo.to_usize()));

                    let mut seen = HashSet::new();
                    for s in v.as_slice().iter() {
                        let lines = cm.span_to_lines(*s);
                        match lines.lines.as_slice() {
                            [line_num, ..] => {
                                let t = (line_num, lines.file.name.clone());
                                if !seen.contains(&t) {
                                    seen.insert(t);
                                    let line = lines.file.get_line(line_num).unwrap();
                                    println!("{}", line);
                                }
                            }
                            _ => { println!("no lines"); }
                        }
                    }
                }
            }
        })
    }
}

pub type Externs = HashMap<String, Vec<String>>;

/// Extract the expanded ast of a krate, along with the codemap which
/// connects source code locations to the actual code.
fn get_ast<F: Fn(&ty::ctxt)>(path: Path,
                             search_paths: SearchPaths, externs: Externs,
                             f: F) {
    use syntax::diagnostic;

    // cargo culted from rustdoc :(
    let input = config::Input::File(path);

    let sessopts = config::Options {
        maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
        externs: externs,
        search_paths: search_paths,
        .. config::basic_options().clone()
    };

    let codemap = syntax::codemap::CodeMap::new();
    let diagnostic_handler =
        diagnostic::default_handler(diagnostic::Auto, None);
    let span_diagnostic_handler =
        diagnostic::mk_span_handler(diagnostic_handler, codemap);

    let sess = session::build_session_(sessopts, None, span_diagnostic_handler);

    let cfg = config::build_configuration(&sess);

    let mut controller = driver::CompileController::basic();
    controller.after_analysis = driver::PhaseController {
        stop: true,
        callback: Box::new(|state| f(state.tcx.unwrap()))
    };

    driver::compile_input(sess, cfg, &input, &None, &None, None, controller);
}
<commit_msg>Update to c5961ad06 2015-01-28 21:49:38 +0000.<commit_after>#![crate_name = "unsafe_ls"]
#![feature(rustc_private, os, core, path, collections, std_misc)]
extern crate arena;
extern crate getopts;
extern crate syntax;
extern crate rustc;
extern crate rustc_back;
extern crate rustc_driver;
extern crate rustc_trans;
extern crate rustc_typeck;

use rustc::session::{self, config};
use rustc_driver::driver;
use rustc::middle::ty;
use rustc::session::search_paths::SearchPaths;
use syntax::codemap::Pos;
use std::collections::{HashSet, HashMap};
use std::os;
use std::sync::Arc;
use std::thread::Thread;

mod visitor;

static DEFAULT_LIB_DIR: &'static str = "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib";

fn main() {
    let args: Vec<_> = std::os::args();
    let opts = [getopts::optflag("h", "help", "show this help message"),
                getopts::optflag("n", "nonffi",
                                 "print `unsafe`s that include non-FFI unsafe behaviours"),
                getopts::optflag("f", "ffi", "print `unsafe`s that do FFI calls"),
                getopts::optmulti("L", "library-path",
                                  "directories to add to crate search path", "DIR")];

    let matches = getopts::getopts(args.tail(), &opts).unwrap();
    if matches.opt_present("help") {
        println!("{}",
                 getopts::usage(format!("{} - find all unsafe blocks and print the \
                                unsafe actions within them", args[0]).as_slice(),
                     &opts));
        return;
    }

    let nonffi = matches.opt_present("nonffi");
    let ffi = matches.opt_present("ffi");
    let mut search_paths = SearchPaths::new();
    for path in matches.opt_strs("L").into_iter() {
        search_paths.add_path(&*path)
    }
    search_paths.add_path(DEFAULT_LIB_DIR);
    let externs = HashMap::new();

    let session = Arc::new(Session {
        nonffi: nonffi,
        ffi: ffi,
        externs: externs,
        search_paths: search_paths,
    });

    for name in matches.free.iter() {
        let sess = session.clone();
        let name = Path::new(name.as_slice());
        let _ = Thread::scoped(move || {
            sess.run_library(name);
        }).join();
    }
}

struct Session {
    nonffi: bool,
    ffi: bool,
    externs: Externs,
    search_paths: SearchPaths,
}

impl Session {
    fn run_library(&self, path: Path) {
        get_ast(path, self.search_paths.clone(), self.externs.clone(), |tcx| {
            let cm = tcx.sess.codemap();

            let mut visitor = visitor::UnsafeVisitor::new(tcx);
            visitor.check_crate(tcx.map.krate());

            for (_, info) in visitor.unsafes.iter() {
                // compiler generated block, so we don't care.
                if info.compiler { continue }

                let n = info.raw_deref.len()
                    + info.static_mut.len()
                    + info.unsafe_call.len()
                    + info.asm.len()
                    + info.transmute.len()
                    + info.transmute_imm_to_mut.len()
                    + info.cast_raw_ptr_const_to_mut.len();

                let f = info.ffi.len();

                if (self.nonffi && n > 0) || (self.ffi && f > 0) {
                    use syntax::codemap::Pos;

                    let mut v = Vec::new();
                    if self.nonffi {
                        for vv in [&info.raw_deref, &info.static_mut,
                                   &info.unsafe_call, &info.asm,
                                   &info.transmute,
                                   &info.transmute_imm_to_mut,
                                   &info.cast_raw_ptr_const_to_mut].iter() {
                            for s in vv.as_slice().iter() {
                                v.push(*s)
                            }
                        }
                    }
                    if self.ffi {
                        for s in info.ffi.as_slice().iter() {
                            v.push(*s)
                        }
                    }

                    let lo = cm.lookup_char_pos_adj(info.span.lo);

                    // print the summary line
                    println!("{}:{}:{}: {} with {:?}",
                             lo.filename,
                             lo.line, lo.col.to_usize() + 1,
                             if info.is_fn {"fn"} else {"block"},
                             *info);

                    // and the individual unsafe actions within each block
                    // (in source order)
                    v.as_mut_slice().sort_by(|a, b| a.lo.to_usize().cmp(&b.lo.to_usize()));

                    let mut seen = HashSet::new();
                    for s in v.as_slice().iter() {
                        let lines = cm.span_to_lines(*s);
                        match lines.lines.as_slice() {
                            [line_num, ..] => {
                                let t = (line_num, lines.file.name.clone());
                                if !seen.contains(&t) {
                                    seen.insert(t);
                                    let line = lines.file.get_line(line_num).unwrap();
                                    println!("{}", line);
                                }
                            }
                            _ => { println!("no lines"); }
                        }
                    }
                }
            }
        })
    }
}

pub type Externs = HashMap<String, Vec<String>>;

/// Extract the expanded ast of a krate, along with the codemap which
/// connects source code locations to the actual code.
fn get_ast<F: Fn(&ty::ctxt)>(path: Path,
                             search_paths: SearchPaths, externs: Externs,
                             f: F) {
    use syntax::diagnostic;

    // cargo culted from rustdoc :(
    let input = config::Input::File(path);

    let sessopts = config::Options {
        maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
        externs: externs,
        search_paths: search_paths,
        .. config::basic_options().clone()
    };

    let codemap = syntax::codemap::CodeMap::new();
    let diagnostic_handler =
        diagnostic::default_handler(diagnostic::Auto, None, true);
    let span_diagnostic_handler =
        diagnostic::mk_span_handler(diagnostic_handler, codemap);

    let sess = session::build_session_(sessopts, None, span_diagnostic_handler);

    let cfg = config::build_configuration(&sess);

    let mut controller = driver::CompileController::basic();
    controller.after_analysis = driver::PhaseController {
        stop: true,
        callback: Box::new(|state| f(state.tcx.unwrap()))
    };

    driver::compile_input(sess, cfg, &input, &None, &None, None, controller);
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 Sajeer Ahamed <ahamedsajeer.15.15@cse.mrt.ac.lk>
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use chrono::TimeZone;
use git2::{Commit, ObjectType, Repository};
use std::{fs, path};

pub fn get_info() {
    let mut commit_id = "UNKNOWN".into();
    let mut commit_date = chrono::Utc::now().format("%Y-%m-%d").to_string();

    let crate_dir = path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let mut repo_dir = crate_dir.clone();

    // First check for a git repository in the manifest directory and if there
    // is none try one directory up in case we're in a Cargo workspace
    let repo = Repository::open(&repo_dir).or_else(move |_| {
        repo_dir.pop();
        Repository::open(&repo_dir)
    });

    let mut release_file = crate_dir.clone();
    release_file.push("release.txt");

    // If there is a git repository, extract the version information from there.
    // Otherwise use a 'release.txt' file as fallback, or report the current
    // date and an unknown revision.
    if let Ok(repo) = repo {
        let commit = find_last_commit(&repo).expect("Couldn't find last commit");
        commit_id = oid_to_short_sha(commit.id());
        let timestamp = commit.time().seconds();
        let dt = chrono::Utc.timestamp(timestamp, 0);
        commit_date = dt.format("%Y-%m-%d").to_string()
    } else if let Ok(release_file) = fs::File::open(release_file) {
        let mut cargo_toml = crate_dir.clone();
        cargo_toml.push("Cargo.toml");

        let cargo_toml = fs::File::open(cargo_toml).expect("Can't open Cargo.toml");
        commit_date = read_release_date(cargo_toml, release_file);
        commit_id = "RELEASE".into();
    }

    println!("cargo:rustc-env=COMMIT_ID={}", commit_id);
    println!("cargo:rustc-env=BUILD_REL_DATE={}", commit_date);
}

fn find_last_commit(repo: &Repository) -> Result<Commit, git2::Error> {
    let obj = repo.head()?.resolve()?.peel(ObjectType::Commit)?;
    obj.into_commit()
        .map_err(|_| git2::Error::from_str("Couldn't find commit"))
}

fn oid_to_short_sha(oid: git2::Oid) -> String {
    oid.to_string()[..8].to_string()
}

fn read_release_date(mut cargo_toml: fs::File, mut release_file: fs::File) -> String {
    use std::io::Read;

    let mut content = String::new();
    release_file
        .read_to_string(&mut content)
        .expect("Failed to read version file");

    let mut lines = content.lines();
    let version = lines.next().expect("Failed to read version number");
    let date = lines.next().expect("Failed to read release date");

    let mut cargo_toml_content = String::new();
    cargo_toml
        .read_to_string(&mut cargo_toml_content)
        .expect("Failed to read `Cargo.toml`");

    let cargo_toml = cargo_toml_content
        .parse::<toml::Value>()
        .expect("Failed to parse `Cargo.toml`");
    let package = cargo_toml["package"]
        .as_table()
        .expect("Failed to find 'package' section in `Cargo.toml`");
    let cargo_version = package["version"]
        .as_str()
        .expect("Failed to read version from `Cargo.toml`");

    if cargo_version != version {
        panic!(
            "Version from 'version.txt' `{}` different from 'Cargo.toml' `{}`",
            version, cargo_version
        );
    }

    date.into()
}
<commit_msg>version-helper: Add documentation<commit_after>// Copyright (C) 2019 Sajeer Ahamed <ahamedsajeer.15.15@cse.mrt.ac.lk>
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Extracts release for [GStreamer](https://gstreamer.freedesktop.org) plugin metadata
//!
//! See [`get_info`](fn.get_info.html) for details.
//!
//! This function is supposed to be used as follows in the `build.rs` of a crate that implements a
//! plugin:
//!
//! ```rust,ignore
//! extern crate gst_plugin_version_helper;
//!
//! fn main() {
//!     gst_plugin_version_helper::get_info()
//! }
//! ```
//!
//! Inside `lib.rs` of the plugin, the information provided by `get_info` are usable as follows:
//!
//! ```rust,ignore
//! gst_plugin_define!(
//!     the_plugin_name,
//!     env!("CARGO_PKG_DESCRIPTION"),
//!     plugin_init,
//!     concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")),
//!     "The Plugin's License",
//!     env!("CARGO_PKG_NAME"),
//!     env!("CARGO_PKG_NAME"),
//!     env!("CARGO_PKG_REPOSITORY"),
//!     env!("BUILD_REL_DATE")
//! );
//! ```

use chrono::TimeZone;
use git2::{Commit, ObjectType, Repository};
use std::{fs, path};

/// Extracts release for GStreamer plugin metadata
///
/// Release information is first tried to be extracted from a git repository at the same
/// place as the `Cargo.toml`, or one directory up to allow for Cargo workspaces. If no
/// git repository is found, the information is extract from a `release.txt` in the same
/// directory as the `Cargo.toml`.
///
/// - If extracted from a git repository, sets the `COMMIT_ID` environment variable to the short
///   commit id of the latest commit and the `BUILD_REL_DATE` environment variable to the date of the
///   commit.
///
/// - If extracted from a `release.txt`, `COMMIT_ID` will be set to the string `RELEASE` and the
///   `BUILD_REL_DATE` variable will be set to the release date extracted from `release.txt`.
///
/// - If neither is possible, `COMMIT_ID` is set to the string `UNKNOWN` and `BUILD_REL_DATE` to the
///   current date.
///
/// ## `release.txt`
///
/// `release.txt` is only parsed if no git repository was found and is assumed to be in the format
///
/// ```txt
/// version_number
/// release_date
/// ```
///
/// for example
///
/// ```txt
/// 1.16.0
/// 2019-04-19
/// ```
///
/// If the version number from `Cargo.toml` is not equivalent to the one in `release.txt`, this
/// function will panic.
pub fn get_info() {
    let mut commit_id = "UNKNOWN".into();
    let mut commit_date = chrono::Utc::now().format("%Y-%m-%d").to_string();

    let crate_dir = path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let mut repo_dir = crate_dir.clone();

    // First check for a git repository in the manifest directory and if there
    // is none try one directory up in case we're in a Cargo workspace
    let repo = Repository::open(&repo_dir).or_else(move |_| {
        repo_dir.pop();
        Repository::open(&repo_dir)
    });

    let mut release_file = crate_dir.clone();
    release_file.push("release.txt");

    // If there is a git repository, extract the version information from there.
    // Otherwise use a 'release.txt' file as fallback, or report the current
    // date and an unknown revision.
    if let Ok(repo) = repo {
        let commit = find_last_commit(&repo).expect("Couldn't find last commit");
        commit_id = oid_to_short_sha(commit.id());
        let timestamp = commit.time().seconds();
        let dt = chrono::Utc.timestamp(timestamp, 0);
        commit_date = dt.format("%Y-%m-%d").to_string()
    } else if let Ok(release_file) = fs::File::open(release_file) {
        let mut cargo_toml = crate_dir.clone();
        cargo_toml.push("Cargo.toml");

        let cargo_toml = fs::File::open(cargo_toml).expect("Can't open Cargo.toml");
        commit_date = read_release_date(cargo_toml, release_file);
        commit_id = "RELEASE".into();
    }

    println!("cargo:rustc-env=COMMIT_ID={}", commit_id);
    println!("cargo:rustc-env=BUILD_REL_DATE={}", commit_date);
}

fn find_last_commit(repo: &Repository) -> Result<Commit, git2::Error> {
    let obj = repo.head()?.resolve()?.peel(ObjectType::Commit)?;
    obj.into_commit()
        .map_err(|_| git2::Error::from_str("Couldn't find commit"))
}

fn oid_to_short_sha(oid: git2::Oid) -> String {
    oid.to_string()[..8].to_string()
}

fn read_release_date(mut cargo_toml: fs::File, mut release_file: fs::File) -> String {
    use std::io::Read;

    let mut content = String::new();
    release_file
        .read_to_string(&mut content)
        .expect("Failed to read version file");

    let mut lines = content.lines();
    let version = lines.next().expect("Failed to read version number");
    let date = lines.next().expect("Failed to read release date");

    let mut cargo_toml_content = String::new();
    cargo_toml
        .read_to_string(&mut cargo_toml_content)
        .expect("Failed to read `Cargo.toml`");

    let cargo_toml = cargo_toml_content
        .parse::<toml::Value>()
        .expect("Failed to parse `Cargo.toml`");
    let package = cargo_toml["package"]
        .as_table()
        .expect("Failed to find 'package' section in `Cargo.toml`");
    let cargo_version = package["version"]
        .as_str()
        .expect("Failed to read version from `Cargo.toml`");

    if cargo_version != version {
        panic!(
            "Version from 'version.txt' `{}` different from 'Cargo.toml' `{}`",
            version, cargo_version
        );
    }

    date.into()
}
<|endoftext|>


<commit_before>
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Lookup result from a resolution of ipv4 and ipv6 records with a Resolver.

use std::error::Error as StdError;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::mem;
use std::slice::Iter;
use std::sync::Arc;

use futures::{Async, future, Future, Poll, task};

use trust_dns_proto::{DnsHandle, RetryDnsHandle};
#[cfg(feature = "dnssec")]
use trust_dns_proto::SecureDnsHandle;
use trust_dns_proto::op::{Message, Query};
use trust_dns_proto::rr::{Name, RecordType, RData};
use trust_dns_proto::rr::rdata;

use error::*;
use lookup_state::CachingClient;
use name_server_pool::{ConnectionProvider, NameServerPool, StandardConnection};
use resolver_future::BasicResolverHandle;

/// Result of a DNS query when querying for any record type supported by the TRust-DNS Client library.
///
/// For IP resolution see LookIp, as it has more features for A and AAAA lookups.
#[derive(Debug, Clone)]
pub struct Lookup {
    rdatas: Arc<Vec<RData>>,
}

impl Lookup {
    /// Return new instance with given rdatas
    pub fn new(rdatas: Arc<Vec<RData>>) -> Self {
        Lookup { rdatas }
    }

    /// Returns a borrowed iterator of the returned IPs
    pub fn iter(&self) -> LookupIter {
        LookupIter(self.rdatas.iter())
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.rdatas.is_empty()
    }

    pub(crate) fn len(&self) -> usize {
        self.rdatas.len()
    }

    /// Clones the inner vec, appends the other vec
    pub(crate) fn append(&self, other: Lookup) -> Self {
        let mut rdatas = Vec::with_capacity(self.len() + other.len());
        rdatas.extend_from_slice(&*self.rdatas);
        rdatas.extend_from_slice(&*other.rdatas);

        Self::new(Arc::new(rdatas))
    }
}

/// Borrowed view of set of RDatas returned from a Lookup
pub struct LookupIter<'a>(Iter<'a, RData>);

impl<'a> Iterator for LookupIter<'a> {
    type Item = &'a RData;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

/// Different lookup options for the lookup attempts and validation
#[derive(Clone)]
#[doc(hidden)]
pub enum LookupEither<C: DnsHandle<Error = ResolveError> + 'static, P: ConnectionProvider<ConnHandle = C> + 'static> {
    Retry(RetryDnsHandle<NameServerPool<C, P>>),
    #[cfg(feature = "dnssec")]
    Secure(SecureDnsHandle<RetryDnsHandle<NameServerPool<C, P>>>),
}

impl<C: DnsHandle<Error = ResolveError>, P: ConnectionProvider<ConnHandle = C>> DnsHandle
    for LookupEither<C, P> {
    type Error = ResolveError;

    fn is_verifying_dnssec(&self) -> bool {
        match *self {
            LookupEither::Retry(ref c) => c.is_verifying_dnssec(),
            #[cfg(feature = "dnssec")]
            LookupEither::Secure(ref c) => c.is_verifying_dnssec(),
        }
    }

    fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
        match *self {
            LookupEither::Retry(ref mut c) => c.send(message),
            #[cfg(feature = "dnssec")]
            LookupEither::Secure(ref mut c) => c.send(message),
        }
    }
}

/// The Future returned from ResolverFuture when performing a lookup.
pub type LookupFuture = InnerLookupFuture<LookupEither<BasicResolverHandle, StandardConnection>>;

/// The Future returned from ResolverFuture when performing a lookup.
#[doc(hidden)]
pub struct InnerLookupFuture<C: DnsHandle<Error = ResolveError> + 'static> {
    client_cache: CachingClient<C>,
    names: Vec<Name>,
    record_type: RecordType,
    future: Box<Future<Item = Lookup, Error = ResolveError>>,
}

impl<C: DnsHandle<Error = ResolveError> + 'static> InnerLookupFuture<C> {
    /// Perform a lookup from a name and type to a set of RDatas
    ///
    /// # Arguments
    ///
    /// * `names` - a set of DNS names to attempt to resolve, they will be attempted in queue order, i.e. the first is `names.pop()`. Upon each failure, the next will be attempted.
    /// * `record_type` - type of record being sought
    /// * `client_cache` - cache with a connection to use for performing all lookups
    #[doc(hidden)]
    pub fn lookup(
        mut names: Vec<Name>,
        record_type: RecordType,
        mut client_cache: CachingClient<C>,
    ) -> Self {
        let name = names.pop().expect("can not lookup IPs for no names");

        let query = client_cache.lookup(Query::query(name, record_type));

        //        let query = lookup(name, record_type, client_cache.clone());
        InnerLookupFuture {
            client_cache: client_cache,
            names,
            record_type,
            future: Box::new(query),
        }
    }

    fn next_lookup<F: FnOnce() -> Poll<Lookup, ResolveError>>(
        &mut self,
        otherwise: F,
    ) -> Poll<Lookup, ResolveError> {
        let name = self.names.pop();
        if let Some(name) = name {
            let query = self.client_cache.lookup(
                Query::query(name, self.record_type),
            );

            mem::replace(&mut self.future, Box::new(query));
            // guarantee that we get scheduled for the next turn...
            task::current().notify();
            Ok(Async::NotReady)
        } else {
            otherwise()
        }
    }

    pub(crate) fn error<E: StdError>(client_cache: CachingClient<C>, error: E) -> Self {
        return InnerLookupFuture {
            // errors on names don't need to be cheap... i.e. this clone is unfortunate in this case.
            client_cache,
            names: vec![],
            record_type: RecordType::NULL,
            future: Box::new(future::err(
                ResolveErrorKind::Msg(format!("{}", error)).into(),
            )),
        };
    }
}

impl<C: DnsHandle<Error = ResolveError> + 'static> Future for InnerLookupFuture<C> {
    type Item = Lookup;
    type Error = ResolveError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.future.poll() {
            Ok(Async::Ready(lookup_ip)) => {
                if lookup_ip.rdatas.len() == 0 {
                    return self.next_lookup(|| Ok(Async::Ready(lookup_ip)));
                } else {
                    return Ok(Async::Ready(lookup_ip));
                }
            }
            p @ Ok(Async::NotReady) => p,
            e @ Err(_) => {
                return self.next_lookup(|| e);
            }
        }
    }
}

/// Creates a Lookup result type from the specified components
macro_rules! lookup_type {
    ($l:ident, $i:ident, $f:ident, $r:path, $t:path) => {
/// Contains the results of a lookup for the associated RecordType
#[derive(Debug, Clone)]
pub struct $l(Lookup);

impl $l {
    /// Returns an iterator over the RData
    pub fn iter(&self) -> $i {
        $i(self.0.iter())
    }
}

impl From<Lookup> for $l {
    fn from(lookup: Lookup) -> Self {
        $l(lookup)
    }
}

/// An iterator over the Lookup type
pub struct $i<'i>(LookupIter<'i>);

impl<'i> Iterator for $i<'i> {
    type Item = &'i $t;

    fn next(&mut self) -> Option<Self::Item> {
        let iter: &mut _ = &mut self.0;
        iter.filter_map(|rdata| match *rdata {
            $r(ref data) => Some(data),
            _ => None,
        }).next()
    }
}

/// A Future while resolves to the Lookup type
pub struct $f(LookupFuture);

impl From<LookupFuture> for $f {
    fn from(lookup_future: LookupFuture) -> Self {
        $f(lookup_future)
    }
}

impl Future for $f {
    type Item = $l;
    type Error = ResolveError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.0.poll() {
            Ok(Async::Ready(lookup)) => Ok(Async::Ready($l(lookup))),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => Err(e),
        }
    }
}
    }
}

// Generate all Lookup record types
lookup_type!(
    ReverseLookup,
    ReverseLookupIter,
    ReverseLookupFuture,
    RData::PTR,
    Name
);
lookup_type!(
    Ipv4Lookup,
    Ipv4LookupIter,
    Ipv4LookupFuture,
    RData::A,
    Ipv4Addr
);
lookup_type!(
    Ipv6Lookup,
    Ipv6LookupIter,
    Ipv6LookupFuture,
    RData::AAAA,
    Ipv6Addr
);
lookup_type!(MxLookup, MxLookupIter, MxLookupFuture, RData::MX, rdata::MX);
lookup_type!(
    SrvLookup,
    SrvLookupIter,
    SrvLookupFuture,
    RData::SRV,
    rdata::SRV
);
lookup_type!(
    TxtLookup,
    TxtLookupIter,
    TxtLookupFuture,
    RData::TXT,
    rdata::TXT
);

#[cfg(test)]
pub mod tests {
    use std::net::{IpAddr, Ipv4Addr};
    use std::sync::{Arc, Mutex};

    use futures::{future, Future};

    use trust_dns_proto::op::Message;
    use trust_dns_proto::rr::{Name, Record, RData, RecordType};

    use super::*;

    #[derive(Clone)]
    pub struct MockDnsHandle {
        messages: Arc<Mutex<Vec<ResolveResult<Message>>>>,
    }

    impl DnsHandle for MockDnsHandle {
        type Error = ResolveError;

        fn send(&mut self, _: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
            Box::new(future::result(
                self.messages.lock().unwrap().pop().unwrap_or(empty()),
            ))
        }
    }

    pub fn v4_message() -> ResolveResult<Message> {
        let mut message = Message::new();
        message.insert_answers(vec![
            Record::from_rdata(
                Name::root(),
                86400,
                RecordType::A,
                RData::A(Ipv4Addr::new(127, 0, 0, 1))
            ),
        ]);
        Ok(message)
    }

    pub fn empty() -> ResolveResult<Message> {
        Ok(Message::new())
    }

    pub fn error() -> ResolveResult<Message> {
        Err(ResolveErrorKind::Io.into())
    }

    pub fn mock(messages: Vec<ResolveResult<Message>>) -> MockDnsHandle {
        MockDnsHandle { messages: Arc::new(Mutex::new(messages)) }
    }

    #[test]
    fn test_lookup() {
        assert_eq!(
            InnerLookupFuture::lookup(
                vec![Name::root()],
                RecordType::A,
                CachingClient::new(0, mock(vec![v4_message()])),
            ).wait()
                .unwrap()
                .iter()
                .map(|r| r.to_ip_addr().unwrap())
                .collect::<Vec<IpAddr>>(),
            vec![Ipv4Addr::new(127, 0, 0, 1)]
        );
    }

    #[test]
    fn test_error() {
        assert!(
            InnerLookupFuture::lookup(
                vec![Name::root()],
                RecordType::A,
                CachingClient::new(0, mock(vec![error()])),
            ).wait()
                .is_err()
        );
    }

    #[test]
    fn test_empty_no_response() {
        assert_eq!(
            InnerLookupFuture::lookup(
                vec![Name::root()],
                RecordType::A,
                CachingClient::new(0, mock(vec![empty()])),
            ).wait()
                .unwrap_err()
                .kind(),
            &ResolveErrorKind::NoRecordsFound(Query::query(Name::root(), RecordType::A))
        );
    }
}
<commit_msg>Fix comment: LookIp -> LookupIp.<commit_after>
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Lookup result from a resolution of ipv4 and ipv6 records with a Resolver.

use std::error::Error as StdError;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::mem;
use std::slice::Iter;
use std::sync::Arc;

use futures::{Async, future, Future, Poll, task};

use trust_dns_proto::{DnsHandle, RetryDnsHandle};
#[cfg(feature = "dnssec")]
use trust_dns_proto::SecureDnsHandle;
use trust_dns_proto::op::{Message, Query};
use trust_dns_proto::rr::{Name, RecordType, RData};
use trust_dns_proto::rr::rdata;

use error::*;
use lookup_state::CachingClient;
use name_server_pool::{ConnectionProvider, NameServerPool, StandardConnection};
use resolver_future::BasicResolverHandle;

/// Result of a DNS query when querying for any record type supported by the TRust-DNS Client library.
///
/// For IP resolution see LookupIp, as it has more features for A and AAAA lookups.
#[derive(Debug, Clone)]
pub struct Lookup {
    rdatas: Arc<Vec<RData>>,
}

impl Lookup {
    /// Return new instance with given rdatas
    pub fn new(rdatas: Arc<Vec<RData>>) -> Self {
        Lookup { rdatas }
    }

    /// Returns a borrowed iterator of the returned IPs
    pub fn iter(&self) -> LookupIter {
        LookupIter(self.rdatas.iter())
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.rdatas.is_empty()
    }

    pub(crate) fn len(&self) -> usize {
        self.rdatas.len()
    }

    /// Clones the inner vec, appends the other vec
    pub(crate) fn append(&self, other: Lookup) -> Self {
        let mut rdatas = Vec::with_capacity(self.len() + other.len());
        rdatas.extend_from_slice(&*self.rdatas);
        rdatas.extend_from_slice(&*other.rdatas);

        Self::new(Arc::new(rdatas))
    }
}

/// Borrowed view of set of RDatas returned from a Lookup
pub struct LookupIter<'a>(Iter<'a, RData>);

impl<'a> Iterator for LookupIter<'a> {
    type Item = &'a RData;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

/// Different lookup options for the lookup attempts and validation
#[derive(Clone)]
#[doc(hidden)]
pub enum LookupEither<C: DnsHandle<Error = ResolveError> + 'static, P: ConnectionProvider<ConnHandle = C> + 'static> {
    Retry(RetryDnsHandle<NameServerPool<C, P>>),
    #[cfg(feature = "dnssec")]
    Secure(SecureDnsHandle<RetryDnsHandle<NameServerPool<C, P>>>),
}

impl<C: DnsHandle<Error = ResolveError>, P: ConnectionProvider<ConnHandle = C>> DnsHandle
    for LookupEither<C, P> {
    type Error = ResolveError;

    fn is_verifying_dnssec(&self) -> bool {
        match *self {
            LookupEither::Retry(ref c) => c.is_verifying_dnssec(),
            #[cfg(feature = "dnssec")]
            LookupEither::Secure(ref c) => c.is_verifying_dnssec(),
        }
    }

    fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
        match *self {
            LookupEither::Retry(ref mut c) => c.send(message),
            #[cfg(feature = "dnssec")]
            LookupEither::Secure(ref mut c) => c.send(message),
        }
    }
}

/// The Future returned from ResolverFuture when performing a lookup.
pub type LookupFuture = InnerLookupFuture<LookupEither<BasicResolverHandle, StandardConnection>>;

/// The Future returned from ResolverFuture when performing a lookup.
#[doc(hidden)]
pub struct InnerLookupFuture<C: DnsHandle<Error = ResolveError> + 'static> {
    client_cache: CachingClient<C>,
    names: Vec<Name>,
    record_type: RecordType,
    future: Box<Future<Item = Lookup, Error = ResolveError>>,
}

impl<C: DnsHandle<Error = ResolveError> + 'static> InnerLookupFuture<C> {
    /// Perform a lookup from a name and type to a set of RDatas
    ///
    /// # Arguments
    ///
    /// * `names` - a set of DNS names to attempt to resolve, they will be attempted in queue order, i.e. the first is `names.pop()`. Upon each failure, the next will be attempted.
    /// * `record_type` - type of record being sought
    /// * `client_cache` - cache with a connection to use for performing all lookups
    #[doc(hidden)]
    pub fn lookup(
        mut names: Vec<Name>,
        record_type: RecordType,
        mut client_cache: CachingClient<C>,
    ) -> Self {
        let name = names.pop().expect("can not lookup IPs for no names");

        let query = client_cache.lookup(Query::query(name, record_type));

        //        let query = lookup(name, record_type, client_cache.clone());
        InnerLookupFuture {
            client_cache: client_cache,
            names,
            record_type,
            future: Box::new(query),
        }
    }

    fn next_lookup<F: FnOnce() -> Poll<Lookup, ResolveError>>(
        &mut self,
        otherwise: F,
    ) -> Poll<Lookup, ResolveError> {
        let name = self.names.pop();
        if let Some(name) = name {
            let query = self.client_cache.lookup(
                Query::query(name, self.record_type),
            );

            mem::replace(&mut self.future, Box::new(query));
            // guarantee that we get scheduled for the next turn...
            task::current().notify();
            Ok(Async::NotReady)
        } else {
            otherwise()
        }
    }

    pub(crate) fn error<E: StdError>(client_cache: CachingClient<C>, error: E) -> Self {
        return InnerLookupFuture {
            // errors on names don't need to be cheap... i.e. this clone is unfortunate in this case.
            client_cache,
            names: vec![],
            record_type: RecordType::NULL,
            future: Box::new(future::err(
                ResolveErrorKind::Msg(format!("{}", error)).into(),
            )),
        };
    }
}

impl<C: DnsHandle<Error = ResolveError> + 'static> Future for InnerLookupFuture<C> {
    type Item = Lookup;
    type Error = ResolveError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.future.poll() {
            Ok(Async::Ready(lookup_ip)) => {
                if lookup_ip.rdatas.len() == 0 {
                    return self.next_lookup(|| Ok(Async::Ready(lookup_ip)));
                } else {
                    return Ok(Async::Ready(lookup_ip));
                }
            }
            p @ Ok(Async::NotReady) => p,
            e @ Err(_) => {
                return self.next_lookup(|| e);
            }
        }
    }
}

/// Creates a Lookup result type from the specified components
macro_rules! lookup_type {
    ($l:ident, $i:ident, $f:ident, $r:path, $t:path) => {
/// Contains the results of a lookup for the associated RecordType
#[derive(Debug, Clone)]
pub struct $l(Lookup);

impl $l {
    /// Returns an iterator over the RData
    pub fn iter(&self) -> $i {
        $i(self.0.iter())
    }
}

impl From<Lookup> for $l {
    fn from(lookup: Lookup) -> Self {
        $l(lookup)
    }
}

/// An iterator over the Lookup type
pub struct $i<'i>(LookupIter<'i>);

impl<'i> Iterator for $i<'i> {
    type Item = &'i $t;

    fn next(&mut self) -> Option<Self::Item> {
        let iter: &mut _ = &mut self.0;
        iter.filter_map(|rdata| match *rdata {
            $r(ref data) => Some(data),
            _ => None,
        }).next()
    }
}

/// A Future while resolves to the Lookup type
pub struct $f(LookupFuture);

impl From<LookupFuture> for $f {
    fn from(lookup_future: LookupFuture) -> Self {
        $f(lookup_future)
    }
}

impl Future for $f {
    type Item = $l;
    type Error = ResolveError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.0.poll() {
            Ok(Async::Ready(lookup)) => Ok(Async::Ready($l(lookup))),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => Err(e),
        }
    }
}
    }
}

// Generate all Lookup record types
lookup_type!(
    ReverseLookup,
    ReverseLookupIter,
    ReverseLookupFuture,
    RData::PTR,
    Name
);
lookup_type!(
    Ipv4Lookup,
    Ipv4LookupIter,
    Ipv4LookupFuture,
    RData::A,
    Ipv4Addr
);
lookup_type!(
    Ipv6Lookup,
    Ipv6LookupIter,
    Ipv6LookupFuture,
    RData::AAAA,
    Ipv6Addr
);
lookup_type!(MxLookup, MxLookupIter, MxLookupFuture, RData::MX, rdata::MX);
lookup_type!(
    SrvLookup,
    SrvLookupIter,
    SrvLookupFuture,
    RData::SRV,
    rdata::SRV
);
lookup_type!(
    TxtLookup,
    TxtLookupIter,
    TxtLookupFuture,
    RData::TXT,
    rdata::TXT
);

#[cfg(test)]
pub mod tests {
    use std::net::{IpAddr, Ipv4Addr};
    use std::sync::{Arc, Mutex};

    use futures::{future, Future};

    use trust_dns_proto::op::Message;
    use trust_dns_proto::rr::{Name, Record, RData, RecordType};

    use super::*;

    #[derive(Clone)]
    pub struct MockDnsHandle {
        messages: Arc<Mutex<Vec<ResolveResult<Message>>>>,
    }

    impl DnsHandle for MockDnsHandle {
        type Error = ResolveError;

        fn send(&mut self, _: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
            Box::new(future::result(
                self.messages.lock().unwrap().pop().unwrap_or(empty()),
            ))
        }
    }

    pub fn v4_message() -> ResolveResult<Message> {
        let mut message = Message::new();
        message.insert_answers(vec![
            Record::from_rdata(
                Name::root(),
                86400,
                RecordType::A,
                RData::A(Ipv4Addr::new(127, 0, 0, 1))
            ),
        ]);
        Ok(message)
    }

    pub fn empty() -> ResolveResult<Message> {
        Ok(Message::new())
    }

    pub fn error() -> ResolveResult<Message> {
        Err(ResolveErrorKind::Io.into())
    }

    pub fn mock(messages: Vec<ResolveResult<Message>>) -> MockDnsHandle {
        MockDnsHandle { messages: Arc::new(Mutex::new(messages)) }
    }

    #[test]
    fn test_lookup() {
        assert_eq!(
            InnerLookupFuture::lookup(
                vec![Name::root()],
                RecordType::A,
                CachingClient::new(0, mock(vec![v4_message()])),
            ).wait()
                .unwrap()
                .iter()
                .map(|r| r.to_ip_addr().unwrap())
                .collect::<Vec<IpAddr>>(),
            vec![Ipv4Addr::new(127, 0, 0, 1)]
        );
    }

    #[test]
    fn test_error() {
        assert!(
            InnerLookupFuture::lookup(
                vec![Name::root()],
                RecordType::A,
                CachingClient::new(0, mock(vec![error()])),
            ).wait()
                .is_err()
        );
    }

    #[test]
    fn test_empty_no_response() {
        assert_eq!(
            InnerLookupFuture::lookup(
                vec![Name::root()],
                RecordType::A,
                CachingClient::new(0, mock(vec![empty()])),
            ).wait()
                .unwrap_err()
                .kind(),
            &ResolveErrorKind::NoRecordsFound(Query::query(Name::root(), RecordType::A))
        );
    }
}
<|endoftext|>


<commit_before>use crate::cpp_data::CppBaseSpecifier;
use crate::cpp_data::CppClassField;
use crate::cpp_data::CppEnumValue;
use crate::cpp_data::CppOriginLocation;
use crate::cpp_data::CppTypeData;
use crate::cpp_data::CppTypeDataKind;
use ritual_common::target::Target;

use crate::cpp_data::CppVisibility;
use crate::cpp_function::CppFunction;

use crate::cpp_data::CppPath;
use crate::cpp_ffi_data::CppFfiFunction;
use crate::cpp_ffi_data::QtSlotWrapper;
use crate::cpp_type::CppType;
use crate::rust_info::RustDatabase;
use itertools::Itertools;
use serde_derive::{Deserialize, Serialize};
use std::fmt::Display;
use std::fmt::Formatter;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerEnv {
    pub target: Target,
    pub cpp_library_version: Option<String>,
}

impl CppCheckerEnv {
    pub fn short_text(&self) -> String {
        format!(
            "{}/{:?}-{:?}-{:?}-{:?}",
            self.cpp_library_version
                .as_ref()
                .map(|s| s.as_str())
                .unwrap_or("None"),
            self.target.arch,
            self.target.os,
            self.target.family,
            self.target.env
        )
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DatabaseItemSource {
    CppParser {
        /// File name of the include file (without full path)
        include_file: String,
        /// Exact location of the declaration
        origin_location: CppOriginLocation,
    },
    ImplicitDestructor,
    TemplateInstantiation,
    NamespaceInfering,
    QtSignalArguments,
}

impl DatabaseItemSource {
    pub fn is_parser(&self) -> bool {
        match *self {
            DatabaseItemSource::CppParser { .. } => true,
            _ => false,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerInfo {
    pub env: CppCheckerEnv,
    pub error: Option<String>,
}

#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerInfoList {
    pub items: Vec<CppCheckerInfo>,
}

pub enum CppCheckerAddResult {
    Added,
    Changed { old: Option<String> },
    Unchanged,
}

impl CppCheckerInfoList {
    pub fn add(&mut self, env: &CppCheckerEnv, error: Option<String>) -> CppCheckerAddResult {
        if let Some(item) = self.items.iter_mut().find(|i| &i.env == env) {
            let r = if item.error == error {
                CppCheckerAddResult::Unchanged
            } else {
                CppCheckerAddResult::Changed {
                    old: item.error.clone(),
                }
            };
            item.error = error;
            return r;
        }
        self.items.push(CppCheckerInfo {
            env: env.clone(),
            error,
        });
        CppCheckerAddResult::Added
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum CppItemData {
    Namespace(CppPath),
    Type(CppTypeData),
    EnumValue(CppEnumValue),
    Function(CppFunction),
    ClassField(CppClassField),
    ClassBase(CppBaseSpecifier),
    QtSignalArguments(Vec<CppType>),
}

impl CppItemData {
    pub fn is_same(&self, other: &CppItemData) -> bool {
        match (self, other) {
            (&CppItemData::Type(ref v), &CppItemData::Type(ref v2)) => v.is_same(v2),
            (&CppItemData::EnumValue(ref v), &CppItemData::EnumValue(ref v2)) => v.is_same(v2),
            (&CppItemData::Function(ref v), &CppItemData::Function(ref v2)) => v.is_same(v2),
            (&CppItemData::ClassField(ref v), &CppItemData::ClassField(ref v2)) => v.is_same(v2),
            (&CppItemData::ClassBase(ref v), &CppItemData::ClassBase(ref v2)) => v == v2,
            (&CppItemData::QtSignalArguments(ref v), &CppItemData::QtSignalArguments(ref v2)) => {
                v == v2
            }
            _ => false,
        }
    }

    pub fn path(&self) -> Option<&CppPath> {
        let path = match self {
            CppItemData::Namespace(data) => data,
            CppItemData::Type(data) => &data.path,
            CppItemData::EnumValue(data) => &data.path,
            CppItemData::Function(data) => &data.path,
            CppItemData::ClassField(data) => &data.path,
            CppItemData::ClassBase(_) | CppItemData::QtSignalArguments(_) => return None,
        };
        Some(path)
    }

    pub fn all_involved_types(&self) -> Vec<CppType> {
        match *self {
            CppItemData::Type(ref t) => match t.kind {
                CppTypeDataKind::Enum => vec![CppType::Enum {
                    path: t.path.clone(),
                }],
                CppTypeDataKind::Class { .. } => vec![CppType::Class(t.path.clone())],
            },
            CppItemData::EnumValue(ref enum_value) => vec![CppType::Enum {
                path: enum_value
                    .path
                    .parent()
                    .expect("enum value must have parent path"),
            }],
            CppItemData::Namespace(_) => Vec::new(),
            CppItemData::Function(ref function) => function.all_involved_types(),
            CppItemData::ClassField(ref field) => {
                let class_type =
                    CppType::Class(field.path.parent().expect("field path must have parent"));
                vec![class_type, field.field_type.clone()]
            }
            CppItemData::ClassBase(ref base) => vec![
                CppType::Class(base.base_class_type.clone()),
                CppType::Class(base.derived_class_type.clone()),
            ],
            CppItemData::QtSignalArguments(ref args) => args.clone(),
        }
    }

    pub fn as_namespace_ref(&self) -> Option<&CppPath> {
        if let CppItemData::Namespace(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_function_ref(&self) -> Option<&CppFunction> {
        if let CppItemData::Function(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_field_ref(&self) -> Option<&CppClassField> {
        if let CppItemData::ClassField(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_enum_value_ref(&self) -> Option<&CppEnumValue> {
        if let CppItemData::EnumValue(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_base_ref(&self) -> Option<&CppBaseSpecifier> {
        if let CppItemData::ClassBase(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_type_ref(&self) -> Option<&CppTypeData> {
        if let CppItemData::Type(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }

    pub fn as_signal_arguments_ref(&self) -> Option<&[CppType]> {
        if let CppItemData::QtSignalArguments(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }

    /*pub fn path(&self) -> Option<String> {
        unimplemented!()
    }*/
}

impl Display for CppItemData {
    fn fmt(&self, f: &mut Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        let s = match *self {
            CppItemData::Namespace(ref path) => format!("namespace {}", path),
            CppItemData::Type(ref type1) => match type1.kind {
                CppTypeDataKind::Enum => format!("enum {}", type1.path.to_cpp_pseudo_code()),
                CppTypeDataKind::Class { .. } => {
                    format!("class {}", type1.path.to_cpp_pseudo_code())
                }
            },
            CppItemData::Function(ref method) => method.short_text(),
            CppItemData::EnumValue(ref value) => {
                format!("enum value {} = {}", value.path, value.value)
            }
            CppItemData::ClassField(ref field) => field.short_text(),
            CppItemData::ClassBase(ref class_base) => {
                let virtual_text = if class_base.is_virtual {
                    "virtual "
                } else {
                    ""
                };
                let visibility_text = match class_base.visibility {
                    CppVisibility::Public => "public",
                    CppVisibility::Protected => "protected",
                    CppVisibility::Private => "private",
                };
                let index_text = if class_base.base_index > 0 {
                    format!(" (index: {}", class_base.base_index)
                } else {
                    String::new()
                };
                format!(
                    "class {} : {}{} {}{}",
                    class_base.derived_class_type.to_cpp_pseudo_code(),
                    virtual_text,
                    visibility_text,
                    class_base.base_class_type.to_cpp_pseudo_code(),
                    index_text
                )
            }
            CppItemData::QtSignalArguments(ref args) => format!(
                "Qt signal args ({})",
                args.iter().map(|arg| arg.to_cpp_pseudo_code()).join(", ")
            ),
        };

        f.write_str(&s)
    }
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CppFfiItemKind {
    Function(CppFfiFunction),

    // TODO: separate custom C++ wrapper logic from core implementation,
    // run cpp_parser on wrappers instead of constructing results manually
    QtSlotWrapper(QtSlotWrapper),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CppFfiItem {
    pub kind: CppFfiItemKind,
    pub checks: CppCheckerInfoList,
    pub is_rust_processed: bool,
}

impl CppFfiItem {
    pub fn from_function(function: CppFfiFunction) -> Self {
        CppFfiItem {
            kind: CppFfiItemKind::Function(function),
            checks: Default::default(),
            is_rust_processed: false,
        }
    }

    pub fn from_qt_slot_wrapper(wrapper: QtSlotWrapper) -> Self {
        CppFfiItem {
            kind: CppFfiItemKind::QtSlotWrapper(wrapper),
            checks: Default::default(),
            is_rust_processed: false,
        }
    }

    pub fn path(&self) -> &CppPath {
        match self.kind {
            CppFfiItemKind::Function(ref f) => &f.path,
            CppFfiItemKind::QtSlotWrapper(ref s) => &s.class_path,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CppDatabaseItem {
    pub cpp_data: CppItemData,

    pub source: DatabaseItemSource,
    pub ffi_items: Vec<CppFfiItem>,
    pub is_cpp_ffi_processed: bool,
    pub is_rust_processed: bool,
}

impl CppDatabaseItem {
    pub fn is_all_rust_processed(&self) -> bool {
        self.is_rust_processed && self.ffi_items.iter().all(|m| m.is_rust_processed)
    }
}

/// Represents all collected data related to a crate.
#[derive(Debug, Serialize, Deserialize)]
pub struct Database {
    pub crate_name: String,
    pub crate_version: String,
    pub cpp_items: Vec<CppDatabaseItem>,
    pub rust_database: RustDatabase,
    pub environments: Vec<CppCheckerEnv>,
}

impl Database {
    pub fn empty(crate_name: impl Into<String>) -> Database {
        Database {
            crate_name: crate_name.into(),
            crate_version: "0.0.0".into(),
            cpp_items: Vec::new(),
            rust_database: Default::default(),
            environments: Vec::new(),
        }
    }

    pub fn items(&self) -> &[CppDatabaseItem] {
        &self.cpp_items
    }

    pub fn clear(&mut self) {
        self.cpp_items.clear();
        self.environments.clear();
    }

    pub fn crate_name(&self) -> &str {
        &self.crate_name
    }

    pub fn add_cpp_data(&mut self, source: DatabaseItemSource, data: CppItemData) -> bool {
        if let Some(item) = self
            .cpp_items
            .iter_mut()
            .find(|item| item.cpp_data.is_same(&data))
        {
            // parser data takes priority
            if source.is_parser() && !item.source.is_parser() {
                item.source = source;
            }
            return false;
        }
        self.cpp_items.push(CppDatabaseItem {
            cpp_data: data,
            source,
            ffi_items: Vec::new(),
            is_cpp_ffi_processed: false,
            is_rust_processed: false,
        });
        true
    }

    /*
    pub fn mark_missing_cpp_data(&mut self, env: DataEnv) {
      let info = DataEnvInfo {
        is_success: false,
        ..DataEnvInfo::default()
      };
      for item in &mut self.items {
        if !item.environments.iter().any(|env2| env2.env == env) {
          item.environments.push(DataEnvWithInfo {
            env: env.clone(),
            info: info.clone(),
          });
        }
      }
    }*/
}
<commit_msg>fix duplicate namespaces in database<commit_after>use crate::cpp_data::CppBaseSpecifier;
use crate::cpp_data::CppClassField;
use crate::cpp_data::CppEnumValue;
use crate::cpp_data::CppOriginLocation;
use crate::cpp_data::CppTypeData;
use crate::cpp_data::CppTypeDataKind;
use ritual_common::target::Target;

use crate::cpp_data::CppVisibility;
use crate::cpp_function::CppFunction;

use crate::cpp_data::CppPath;
use crate::cpp_ffi_data::CppFfiFunction;
use crate::cpp_ffi_data::QtSlotWrapper;
use crate::cpp_type::CppType;
use crate::rust_info::RustDatabase;
use itertools::Itertools;
use serde_derive::{Deserialize, Serialize};
use std::fmt::Display;
use std::fmt::Formatter;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerEnv {
    pub target: Target,
    pub cpp_library_version: Option<String>,
}

impl CppCheckerEnv {
    pub fn short_text(&self) -> String {
        format!(
            "{}/{:?}-{:?}-{:?}-{:?}",
            self.cpp_library_version
                .as_ref()
                .map(|s| s.as_str())
                .unwrap_or("None"),
            self.target.arch,
            self.target.os,
            self.target.family,
            self.target.env
        )
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DatabaseItemSource {
    CppParser {
        /// File name of the include file (without full path)
        include_file: String,
        /// Exact location of the declaration
        origin_location: CppOriginLocation,
    },
    ImplicitDestructor,
    TemplateInstantiation,
    NamespaceInfering,
    QtSignalArguments,
}

impl DatabaseItemSource {
    pub fn is_parser(&self) -> bool {
        match *self {
            DatabaseItemSource::CppParser { .. } => true,
            _ => false,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerInfo {
    pub env: CppCheckerEnv,
    pub error: Option<String>,
}

#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerInfoList {
    pub items: Vec<CppCheckerInfo>,
}

pub enum CppCheckerAddResult {
    Added,
    Changed { old: Option<String> },
    Unchanged,
}

impl CppCheckerInfoList {
    pub fn add(&mut self, env: &CppCheckerEnv, error: Option<String>) -> CppCheckerAddResult {
        if let Some(item) = self.items.iter_mut().find(|i| &i.env == env) {
            let r = if item.error == error {
                CppCheckerAddResult::Unchanged
            } else {
                CppCheckerAddResult::Changed {
                    old: item.error.clone(),
                }
            };
            item.error = error;
            return r;
        }
        self.items.push(CppCheckerInfo {
            env: env.clone(),
            error,
        });
        CppCheckerAddResult::Added
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum CppItemData {
    Namespace(CppPath),
    Type(CppTypeData),
    EnumValue(CppEnumValue),
    Function(CppFunction),
    ClassField(CppClassField),
    ClassBase(CppBaseSpecifier),
    QtSignalArguments(Vec<CppType>),
}

impl CppItemData {
    pub fn is_same(&self, other: &CppItemData) -> bool {
        match (self, other) {
            (&CppItemData::Namespace(ref v), &CppItemData::Namespace(ref v2)) => v == v2,
            (&CppItemData::Type(ref v), &CppItemData::Type(ref v2)) => v.is_same(v2),
            (&CppItemData::EnumValue(ref v), &CppItemData::EnumValue(ref v2)) => v.is_same(v2),
            (&CppItemData::Function(ref v), &CppItemData::Function(ref v2)) => v.is_same(v2),
            (&CppItemData::ClassField(ref v), &CppItemData::ClassField(ref v2)) => v.is_same(v2),
            (&CppItemData::ClassBase(ref v), &CppItemData::ClassBase(ref v2)) => v == v2,
            (&CppItemData::QtSignalArguments(ref v), &CppItemData::QtSignalArguments(ref v2)) => {
                v == v2
            }
            _ => false,
        }
    }

    pub fn path(&self) -> Option<&CppPath> {
        let path = match self {
            CppItemData::Namespace(data) => data,
            CppItemData::Type(data) => &data.path,
            CppItemData::EnumValue(data) => &data.path,
            CppItemData::Function(data) => &data.path,
            CppItemData::ClassField(data) => &data.path,
            CppItemData::ClassBase(_) | CppItemData::QtSignalArguments(_) => return None,
        };
        Some(path)
    }

    pub fn all_involved_types(&self) -> Vec<CppType> {
        match *self {
            CppItemData::Type(ref t) => match t.kind {
                CppTypeDataKind::Enum => vec![CppType::Enum {
                    path: t.path.clone(),
                }],
                CppTypeDataKind::Class { .. } => vec![CppType::Class(t.path.clone())],
            },
            CppItemData::EnumValue(ref enum_value) => vec![CppType::Enum {
                path: enum_value
                    .path
                    .parent()
                    .expect("enum value must have parent path"),
            }],
            CppItemData::Namespace(_) => Vec::new(),
            CppItemData::Function(ref function) => function.all_involved_types(),
            CppItemData::ClassField(ref field) => {
                let class_type =
                    CppType::Class(field.path.parent().expect("field path must have parent"));
                vec![class_type, field.field_type.clone()]
            }
            CppItemData::ClassBase(ref base) => vec![
                CppType::Class(base.base_class_type.clone()),
                CppType::Class(base.derived_class_type.clone()),
            ],
            CppItemData::QtSignalArguments(ref args) => args.clone(),
        }
    }

    pub fn as_namespace_ref(&self) -> Option<&CppPath> {
        if let CppItemData::Namespace(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_function_ref(&self) -> Option<&CppFunction> {
        if let CppItemData::Function(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_field_ref(&self) -> Option<&CppClassField> {
        if let CppItemData::ClassField(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_enum_value_ref(&self) -> Option<&CppEnumValue> {
        if let CppItemData::EnumValue(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_base_ref(&self) -> Option<&CppBaseSpecifier> {
        if let CppItemData::ClassBase(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }
    pub fn as_type_ref(&self) -> Option<&CppTypeData> {
        if let CppItemData::Type(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }

    pub fn as_signal_arguments_ref(&self) -> Option<&[CppType]> {
        if let CppItemData::QtSignalArguments(ref data) = *self {
            Some(data)
        } else {
            None
        }
    }

    /*pub fn path(&self) -> Option<String> {
        unimplemented!()
    }*/
}

impl Display for CppItemData {
    fn fmt(&self, f: &mut Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        let s = match *self {
            CppItemData::Namespace(ref path) => format!("namespace {}", path),
            CppItemData::Type(ref type1) => match type1.kind {
                CppTypeDataKind::Enum => format!("enum {}", type1.path.to_cpp_pseudo_code()),
                CppTypeDataKind::Class { .. } => {
                    format!("class {}", type1.path.to_cpp_pseudo_code())
                }
            },
            CppItemData::Function(ref method) => method.short_text(),
            CppItemData::EnumValue(ref value) => {
                format!("enum value {} = {}", value.path, value.value)
            }
            CppItemData::ClassField(ref field) => field.short_text(),
            CppItemData::ClassBase(ref class_base) => {
                let virtual_text = if class_base.is_virtual {
                    "virtual "
                } else {
                    ""
                };
                let visibility_text = match class_base.visibility {
                    CppVisibility::Public => "public",
                    CppVisibility::Protected => "protected",
                    CppVisibility::Private => "private",
                };
                let index_text = if class_base.base_index > 0 {
                    format!(" (index: {}", class_base.base_index)
                } else {
                    String::new()
                };
                format!(
                    "class {} : {}{} {}{}",
                    class_base.derived_class_type.to_cpp_pseudo_code(),
                    virtual_text,
                    visibility_text,
                    class_base.base_class_type.to_cpp_pseudo_code(),
                    index_text
                )
            }
            CppItemData::QtSignalArguments(ref args) => format!(
                "Qt signal args ({})",
                args.iter().map(|arg| arg.to_cpp_pseudo_code()).join(", ")
            ),
        };

        f.write_str(&s)
    }
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CppFfiItemKind {
    Function(CppFfiFunction),

    // TODO: separate custom C++ wrapper logic from core implementation,
    // run cpp_parser on wrappers instead of constructing results manually
    QtSlotWrapper(QtSlotWrapper),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CppFfiItem {
    pub kind: CppFfiItemKind,
    pub checks: CppCheckerInfoList,
    pub is_rust_processed: bool,
}

impl CppFfiItem {
    pub fn from_function(function: CppFfiFunction) -> Self {
        CppFfiItem {
            kind: CppFfiItemKind::Function(function),
            checks: Default::default(),
            is_rust_processed: false,
        }
    }

    pub fn from_qt_slot_wrapper(wrapper: QtSlotWrapper) -> Self {
        CppFfiItem {
            kind: CppFfiItemKind::QtSlotWrapper(wrapper),
            checks: Default::default(),
            is_rust_processed: false,
        }
    }

    pub fn path(&self) -> &CppPath {
        match self.kind {
            CppFfiItemKind::Function(ref f) => &f.path,
            CppFfiItemKind::QtSlotWrapper(ref s) => &s.class_path,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CppDatabaseItem {
    pub cpp_data: CppItemData,

    pub source: DatabaseItemSource,
    pub ffi_items: Vec<CppFfiItem>,
    pub is_cpp_ffi_processed: bool,
    pub is_rust_processed: bool,
}

impl CppDatabaseItem {
    pub fn is_all_rust_processed(&self) -> bool {
        self.is_rust_processed && self.ffi_items.iter().all(|m| m.is_rust_processed)
    }
}

/// Represents all collected data related to a crate.
#[derive(Debug, Serialize, Deserialize)]
pub struct Database {
    pub crate_name: String,
    pub crate_version: String,
    pub cpp_items: Vec<CppDatabaseItem>,
    pub rust_database: RustDatabase,
    pub environments: Vec<CppCheckerEnv>,
}

impl Database {
    pub fn empty(crate_name: impl Into<String>) -> Database {
        Database {
            crate_name: crate_name.into(),
            crate_version: "0.0.0".into(),
            cpp_items: Vec::new(),
            rust_database: Default::default(),
            environments: Vec::new(),
        }
    }

    pub fn items(&self) -> &[CppDatabaseItem] {
        &self.cpp_items
    }

    pub fn clear(&mut self) {
        self.cpp_items.clear();
        self.environments.clear();
    }

    pub fn crate_name(&self) -> &str {
        &self.crate_name
    }

    pub fn add_cpp_data(&mut self, source: DatabaseItemSource, data: CppItemData) -> bool {
        if let Some(item) = self
            .cpp_items
            .iter_mut()
            .find(|item| item.cpp_data.is_same(&data))
        {
            // parser data takes priority
            if source.is_parser() && !item.source.is_parser() {
                item.source = source;
            }
            return false;
        }
        self.cpp_items.push(CppDatabaseItem {
            cpp_data: data,
            source,
            ffi_items: Vec::new(),
            is_cpp_ffi_processed: false,
            is_rust_processed: false,
        });
        true
    }

    /*
    pub fn mark_missing_cpp_data(&mut self, env: DataEnv) {
      let info = DataEnvInfo {
        is_success: false,
        ..DataEnvInfo::default()
      };
      for item in &mut self.items {
        if !item.environments.iter().any(|env2| env2.env == env) {
          item.environments.push(DataEnvWithInfo {
            env: env.clone(),
            info: info.clone(),
          });
        }
      }
    }*/
}
<|endoftext|>


<commit_before>//! A partially ordered measure of progress at each timely dataflow location.

use std::fmt::Debug;
use std::any::Any;
use std::default::Default;
use std::fmt::Formatter;
use std::fmt::Error;
use std::hash::Hash;

use order::PartialOrder;
use progress::nested::product::Product;

use abomonation::Abomonation;

// TODO : Change Copy requirement to Clone;
/// A composite trait for types that serve as timestamps in timely dataflow.
pub trait Timestamp: Clone+Eq+PartialOrder+Default+Debug+Send+Any+Abomonation+Hash {
    /// A type summarizing action on a timestamp along a dataflow path.
    type Summary : PathSummary<Self> + 'static;
}

// TODO : Change Copy requirement to Clone
// TODO : Change `results_in` and perhaps `followed_by` to return an `Option`, indicating no path.
// TODO : This can be important when a summary would "overflow", as we want neither to overflow,
// TODO : nor wrap around, nor saturate.
/// A summary of how a timestamp advances along a timely dataflow path.
pub trait PathSummary<T> : Clone+'static+Eq+PartialOrder+Debug+Default {
    /// Advances a timestamp according to the timestamp actions on the path.
    ///
    /// The path may advance the timestamp sufficiently that it is no longer valid, for example if
    /// incrementing fields would result in integer overflow. In this case, `results_in` should
    /// return `None`.
    ///
    /// The `feedback` operator, apparently the only point where timestamps are actually incremented
    /// in computation, uses this method and will drop messages with timestamps that when advanced
    /// result in `None`. Ideally, all other timestamp manipulation should behave similarly.
    ///
    /// #Examples
    /// ```
    /// use timely::progress::timestamp::PathSummary;
    ///
    /// let timestamp = 3;
    ///
    /// let summary1 = 5;
    /// let summary2 = usize::max_value() - 2;
    ///
    /// assert_eq!(summary1.results_in(&timestamp), Some(8));
    /// assert_eq!(summary2.results_in(&timestamp), None);
    /// ```
    fn results_in(&self, src: &T) -> Option<T>;
    /// Composes this path summary with another path summary.
    ///
    /// It is possible that the two composed paths result in an invalid summary, for example when
    /// integer additions overflow. If it is correct that all timestamps moved along these paths
    /// would also result in overflow and be discarded, `followed_by` can return `None. It is very
    /// important that this not be used casually, as this does not prevent the actual movement of
    /// data.
    ///
    /// #Examples
    /// ```
    /// use timely::progress::timestamp::PathSummary;
    ///
    /// let summary1 = 5;
    /// let summary2 = usize::max_value() - 3;
    ///
    /// assert_eq!(summary1.followed_by(&summary2), None);
    /// ```
    fn followed_by(&self, other: &Self) -> Option<Self>;
}

/// An empty timestamp used by the root scope.
#[derive(Copy, Clone, Hash, Eq, Ord, PartialOrd, PartialEq, Default)]
pub struct RootTimestamp;
impl Timestamp for RootTimestamp { type Summary = RootSummary; }
impl Debug for RootTimestamp {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str("Root")
    }
}

impl PartialOrder for RootTimestamp { #[inline(always)] fn less_equal(&self, _other: &Self) -> bool { true } }

impl Abomonation for RootTimestamp { }
impl RootTimestamp {
    /// Constructs a new `Product<RootTimestamp,T>`.
    #[inline]
    pub fn new<T: Timestamp>(t: T) -> Product<RootTimestamp, T> {
        Product::new(RootTimestamp, t)
    }
}

/// An empty path summary for root timestamps.
#[derive(Copy, Clone, Eq, Ord, PartialOrd, PartialEq, Debug, Default)]
pub struct RootSummary;
impl PathSummary<RootTimestamp> for RootSummary {
    #[inline]
    fn results_in(&self, _: &RootTimestamp) -> Option<RootTimestamp> { Some(RootTimestamp) }
    #[inline]
    fn followed_by(&self, _: &RootSummary) -> Option<RootSummary> { Some(RootSummary) }
}

impl PartialOrder for RootSummary { #[inline(always)] fn less_equal(&self, _other: &Self) -> bool { true } }

impl Timestamp for () { type Summary = (); }
impl PathSummary<()> for () {
    fn results_in(&self, _src: &()) -> Option<()> { Some(()) }
    fn followed_by(&self, _other: &()) -> Option<()> { Some(()) }
}

impl Timestamp for usize { type Summary = usize; }
impl PathSummary<usize> for usize {
    #[inline]
    fn results_in(&self, src: &usize) -> Option<usize> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &usize) -> Option<usize> { self.checked_add(*other) }
}

impl Timestamp for u64 { type Summary = u64; }
impl PathSummary<u64> for u64 {
    #[inline]
    fn results_in(&self, src: &u64) -> Option<u64> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &u64) -> Option<u64> { self.checked_add(*other) }
}

impl Timestamp for u32 { type Summary = u32; }
impl PathSummary<u32> for u32 {
    #[inline]
    fn results_in(&self, src: &u32) -> Option<u32> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &u32) -> Option<u32> { self.checked_add(*other) }
}

impl Timestamp for i32 { type Summary = i32; }
impl PathSummary<i32> for i32 {
    #[inline]
    fn results_in(&self, src: &i32) -> Option<i32> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &i32) -> Option<i32> { self.checked_add(*other) }
}
<commit_msg>add Ord to Timestamp<commit_after>//! A partially ordered measure of progress at each timely dataflow location.

use std::fmt::Debug;
use std::any::Any;
use std::default::Default;
use std::fmt::Formatter;
use std::fmt::Error;
use std::hash::Hash;

use order::PartialOrder;
use progress::nested::product::Product;

use abomonation::Abomonation;

// TODO : Change Copy requirement to Clone;
/// A composite trait for types that serve as timestamps in timely dataflow.
pub trait Timestamp: Clone+Eq+PartialOrder+Default+Debug+Send+Any+Abomonation+Hash+Ord {
    /// A type summarizing action on a timestamp along a dataflow path.
    type Summary : PathSummary<Self> + 'static;
}

// TODO : Change Copy requirement to Clone
// TODO : Change `results_in` and perhaps `followed_by` to return an `Option`, indicating no path.
// TODO : This can be important when a summary would "overflow", as we want neither to overflow,
// TODO : nor wrap around, nor saturate.
/// A summary of how a timestamp advances along a timely dataflow path.
pub trait PathSummary<T> : Clone+'static+Eq+PartialOrder+Debug+Default {
    /// Advances a timestamp according to the timestamp actions on the path.
    ///
    /// The path may advance the timestamp sufficiently that it is no longer valid, for example if
    /// incrementing fields would result in integer overflow. In this case, `results_in` should
    /// return `None`.
    ///
    /// The `feedback` operator, apparently the only point where timestamps are actually incremented
    /// in computation, uses this method and will drop messages with timestamps that when advanced
    /// result in `None`. Ideally, all other timestamp manipulation should behave similarly.
    ///
    /// #Examples
    /// ```
    /// use timely::progress::timestamp::PathSummary;
    ///
    /// let timestamp = 3;
    ///
    /// let summary1 = 5;
    /// let summary2 = usize::max_value() - 2;
    ///
    /// assert_eq!(summary1.results_in(&timestamp), Some(8));
    /// assert_eq!(summary2.results_in(&timestamp), None);
    /// ```
    fn results_in(&self, src: &T) -> Option<T>;
    /// Composes this path summary with another path summary.
    ///
    /// It is possible that the two composed paths result in an invalid summary, for example when
    /// integer additions overflow. If it is correct that all timestamps moved along these paths
    /// would also result in overflow and be discarded, `followed_by` can return `None. It is very
    /// important that this not be used casually, as this does not prevent the actual movement of
    /// data.
    ///
    /// #Examples
    /// ```
    /// use timely::progress::timestamp::PathSummary;
    ///
    /// let summary1 = 5;
    /// let summary2 = usize::max_value() - 3;
    ///
    /// assert_eq!(summary1.followed_by(&summary2), None);
    /// ```
    fn followed_by(&self, other: &Self) -> Option<Self>;
}

/// An empty timestamp used by the root scope.
#[derive(Copy, Clone, Hash, Eq, Ord, PartialOrd, PartialEq, Default)]
pub struct RootTimestamp;
impl Timestamp for RootTimestamp { type Summary = RootSummary; }
impl Debug for RootTimestamp {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str("Root")
    }
}

impl PartialOrder for RootTimestamp { #[inline(always)] fn less_equal(&self, _other: &Self) -> bool { true } }

impl Abomonation for RootTimestamp { }
impl RootTimestamp {
    /// Constructs a new `Product<RootTimestamp,T>`.
    #[inline]
    pub fn new<T: Timestamp>(t: T) -> Product<RootTimestamp, T> {
        Product::new(RootTimestamp, t)
    }
}

/// An empty path summary for root timestamps.
#[derive(Copy, Clone, Eq, Ord, PartialOrd, PartialEq, Debug, Default)]
pub struct RootSummary;
impl PathSummary<RootTimestamp> for RootSummary {
    #[inline]
    fn results_in(&self, _: &RootTimestamp) -> Option<RootTimestamp> { Some(RootTimestamp) }
    #[inline]
    fn followed_by(&self, _: &RootSummary) -> Option<RootSummary> { Some(RootSummary) }
}

impl PartialOrder for RootSummary { #[inline(always)] fn less_equal(&self, _other: &Self) -> bool { true } }

impl Timestamp for () { type Summary = (); }
impl PathSummary<()> for () {
    fn results_in(&self, _src: &()) -> Option<()> { Some(()) }
    fn followed_by(&self, _other: &()) -> Option<()> { Some(()) }
}

impl Timestamp for usize { type Summary = usize; }
impl PathSummary<usize> for usize {
    #[inline]
    fn results_in(&self, src: &usize) -> Option<usize> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &usize) -> Option<usize> { self.checked_add(*other) }
}

impl Timestamp for u64 { type Summary = u64; }
impl PathSummary<u64> for u64 {
    #[inline]
    fn results_in(&self, src: &u64) -> Option<u64> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &u64) -> Option<u64> { self.checked_add(*other) }
}

impl Timestamp for u32 { type Summary = u32; }
impl PathSummary<u32> for u32 {
    #[inline]
    fn results_in(&self, src: &u32) -> Option<u32> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &u32) -> Option<u32> { self.checked_add(*other) }
}

impl Timestamp for i32 { type Summary = i32; }
impl PathSummary<i32> for i32 {
    #[inline]
    fn results_in(&self, src: &i32) -> Option<i32> { self.checked_add(*src) }
    #[inline]
    fn followed_by(&self, other: &i32) -> Option<i32> { self.checked_add(*other) }
}
<|endoftext|>