<commit_before>// Copyright 2015 Bobby Powers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//extern crate libc;
//use libc::geteuid;

use std::cmp::{Eq, Ordering};
use std::fs::{self, File};
use std::io::{Error, ErrorKind, Read, Result};

const PROC_PATH: &'static str = "/proc";

struct CmdStat {
    name: String,
    pss: f32,
    shared: f32,
    heap: f32,
    swap: f32,
}

impl PartialEq for CmdStat {
    fn eq(&self, other: &CmdStat) -> bool {
        self.name == other.name
    }
}
impl Eq for CmdStat {}

impl PartialOrd for CmdStat {
    fn partial_cmp(&self, other: &CmdStat) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CmdStat {
    fn cmp(&self, other: &CmdStat) -> Ordering {
        self.name.cmp(&other.name)
    }
}

#[inline(never)]
fn is_digit(d: char) -> bool {
    d >= '0' && d <= '9'
}

#[inline(never)]
fn first_char(name: &std::ffi::OsStr) -> char {
    use std::os::unix::ffi::OsStrExt;
    name.as_bytes()[0] as char
}

fn is_dir(md: fs::Metadata) -> Result<fs::Metadata> {
    if md.is_dir() {
        Ok(md)
    } else {
        Err(Error::new(ErrorKind::NotFound, "not a directory"))
    }
}

#[inline(never)]
fn get_pids() -> Result<Vec<i32>> {
    let dir = fs::read_dir(PROC_PATH)?;

    // TODO: look at filter_map
    let pids: Vec<i32> = dir
        .filter(|e| e.is_ok()) // ignore bad dirent results
        .map(|e| e.unwrap()) // make this a list of dirents
        .filter(|e| is_digit(first_char(&e.file_name())))
        .filter(|e| fs::metadata(e.path()).and_then(|md| is_dir(md)).is_ok())
        .map(|e| i32::from_str_radix(e.file_name().to_str().unwrap(), 10).unwrap())
        .collect();

    Ok(pids)
}

fn proc_cmdline(pid: i32) -> Result<String> {
    let mut buf = String::new();
    let path = format!("/proc/{}/cmdline", pid);

    // TODO: we don't really care about reading all of the
    // cmdline, just the first 1024 chars is enough.
    let mut f = File::open(path)?;

    f.read_to_string(&mut buf)?;

    Ok(buf)
}

fn proc_name(pid: i32) -> Result<String> {
    let path = format!("/proc/{}/exe", pid);

    let owned_path = fs::read_link(path)?;
    let full_path = owned_path.to_string_lossy();
    let cmdline = proc_cmdline(pid)?;

    let result = if cmdline.starts_with(&*full_path) {
        // the basename (last component) of the path
        owned_path
            .file_name()
            .unwrap()
            .to_string_lossy()
            .to_string()
    } else {
        cmdline
    };

    Ok(result)
}

fn cmdstat_new(pid: i32) -> Option<CmdStat> {
    match proc_name(pid) {
        Ok(name) => Some(CmdStat {
            name: name,
            pss: 0.0,
            shared: 0.0,
            heap: 0.0,
            swap: 0.0,
        }),
        Err(_) => None,
    }
}

fn cmdstats_for(pids: Vec<i32>) -> Vec<CmdStat> {
    pids.into_iter().filter_map(cmdstat_new).collect()
}

fn main() {
    // command line flag parsing

    // check euid
    // unsafe {
    // 	let uid = geteuid();
    // 	if uid != 0 {
    // 	    println!("we aren't root");
    // 	}
    // }

    let pids_r = get_pids();
    if let Err(err) = pids_r {
        println!("get_pids: {}", err);
        return;
    }

    let pids = pids_r.unwrap();

    let mut stats = cmdstats_for(pids);

    stats.sort_unstable();

    // merge adjacent/find total

    // print_results
}
<commit_msg>read smaps_rollup<commit_after>// Copyright 2015 Bobby Powers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//extern crate libc;
//use libc::geteuid;

use std::cmp::{Eq, Ordering};
use std::fs::{self, File};
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Result};

const PROC_PATH: &'static str = "/proc";

const TY_PSS: &'static str = "Pss:";
const TY_SWAP: &'static str = "Swap:";
const TY_PRIVATE_CLEAN: &'static str = "Private_Clean:";
const TY_PRIVATE_DIRTY: &'static str = "Private_Dirty:";

struct CmdStat {
    name: String,
    pid: i32,
    pss: f32,
    shared: f32,
    swap: f32,
}

impl CmdStat {
    fn new(pid: i32) -> Result<CmdStat> {
        let name = proc_name(pid)?;

        let mut stats = CmdStat {
            name: name,
            pid: pid,
            pss: 0.0,
            shared: 0.0,
            swap: 0.0,
        };

        stats.collect_memory_usage()?;

        Ok(stats)
    }

    fn collect_memory_usage(&mut self) -> Result<()> {
        let path = format!("/proc/{}/smaps_rollup", self.pid);
        let file = File::open(path)?;

        let mut private: f32 = 0.0;

        for line in BufReader::new(file).lines() {
            let line = line.unwrap();
            if line.starts_with(TY_PSS) {
                if let Ok(n) = parse_line(&line) {
                    self.pss += n;
                }
            } else if line.starts_with(TY_SWAP) {
                if let Ok(n) = parse_line(&line) {
                    self.swap += n;
                }
            } else if line.starts_with(TY_PRIVATE_CLEAN) || line.starts_with(TY_PRIVATE_DIRTY) {
                if let Ok(n) = parse_line(&line) {
                    private += n;
                }
            }
        }

        self.shared = self.pss - private;

        Ok(())
    }
}

fn parse_line(line: &str) -> Result<f32> {
    let kbs = &line[16..24];
    let num: f32 = kbs
        .trim_start()
        .parse()
        .map_err(|_e| Error::new(ErrorKind::Other, "parse error"))?;
    Ok(num)
}

impl PartialEq for CmdStat {
    fn eq(&self, other: &CmdStat) -> bool {
        self.name == other.name
    }
}
impl Eq for CmdStat {}

impl PartialOrd for CmdStat {
    fn partial_cmp(&self, other: &CmdStat) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CmdStat {
    fn cmp(&self, other: &CmdStat) -> Ordering {
        self.name.cmp(&other.name)
    }
}

#[inline(never)]
fn is_digit(d: char) -> bool {
    d >= '0' && d <= '9'
}

#[inline(never)]
fn first_char(name: &std::ffi::OsStr) -> char {
    use std::os::unix::ffi::OsStrExt;
    name.as_bytes()[0] as char
}

fn is_dir(md: fs::Metadata) -> Result<fs::Metadata> {
    if md.is_dir() {
        Ok(md)
    } else {
        Err(Error::new(ErrorKind::NotFound, "not a directory"))
    }
}

#[inline(never)]
fn get_pids() -> Result<Vec<i32>> {
    let dir = fs::read_dir(PROC_PATH)?;

    // TODO: look at filter_map
    let pids: Vec<i32> = dir
        .filter(|e| e.is_ok()) // ignore bad dirent results
        .map(|e| e.unwrap()) // make this a list of dirents
        .filter(|e| is_digit(first_char(&e.file_name())))
        .filter(|e| fs::metadata(e.path()).and_then(|md| is_dir(md)).is_ok())
        .map(|e| i32::from_str_radix(e.file_name().to_str().unwrap(), 10).unwrap())
        .collect();

    Ok(pids)
}

fn proc_cmdline(pid: i32) -> Result<String> {
    let mut buf = String::new();
    let path = format!("/proc/{}/cmdline", pid);

    // TODO: we don't really care about reading all of the
    // cmdline, just the first 1024 chars is enough.
    let mut f = File::open(path)?;

    f.read_to_string(&mut buf)?;

    Ok(buf)
}

fn proc_name(pid: i32) -> Result<String> {
    let path = format!("/proc/{}/exe", pid);

    let owned_path = fs::read_link(path)?;
    let full_path = owned_path.to_string_lossy();
    let cmdline = proc_cmdline(pid)?;

    let result = if cmdline.starts_with(&*full_path) {
        // the basename (last component) of the path
        owned_path
            .file_name()
            .unwrap()
            .to_string_lossy()
            .to_string()
    } else {
        cmdline
    };

    Ok(result)
}

fn cmdstats_for(pids: Vec<i32>) -> Vec<CmdStat> {
    pids.into_iter()
        .filter_map(|pid| CmdStat::new(pid).ok())
        .collect()
}

fn main() {
    // command line flag parsing

    // check euid
    // unsafe {
    // 	let uid = geteuid();
    // 	if uid != 0 {
    // 	    println!("we aren't root");
    // 	}
    // }

    let pids_r = get_pids();
    if let Err(err) = pids_r {
        println!("get_pids: {}", err);
        return;
    }

    let pids = pids_r.unwrap();

    let mut stats = cmdstats_for(pids);

    stats.sort_unstable();

    // merge adjacent/find total

    // print_results
}
<|endoftext|>


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

//! Unsafe casting functions

use ptr::RawPtr;
use mem;
use unstable::intrinsics;
use ptr::copy_nonoverlapping_memory;

/// Casts the value at `src` to U. The two types must have the same length.
#[inline]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
    let mut dest: U = intrinsics::uninit();
    let dest_ptr: *mut u8 = transmute(&mut dest);
    let src_ptr: *u8 = transmute(src);
    copy_nonoverlapping_memory(dest_ptr, src_ptr, mem::size_of::<U>());
    dest
}

/**
 * Forces a copy of a value, even if that value is considered noncopyable.
 */
#[inline]
pub unsafe fn unsafe_copy<T>(thing: &T) -> T {
    transmute_copy(thing)
}

/**
 * Move a thing into the void
 *
 * The forget function will take ownership of the provided value but neglect
 * to run any required cleanup or memory-management operations on it. This
 * can be used for various acts of magick.
 */
#[inline]
pub unsafe fn forget<T>(thing: T) { intrinsics::forget(thing); }

/**
 * Force-increment the reference count on a shared box. If used
 * carelessly, this can leak the box.
 */
#[inline]
pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }

/**
 * Transform a value of one type into a value of another type.
 * Both types must have the same size and alignment.
 *
 * # Example
 *
 * ```rust
 * let v: &[u8] = transmute("L");
 * assert!(v == [76u8]);
 * ```
 */
#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
    intrinsics::transmute(thing)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }

/// Coerce a mutable reference to be immutable.
#[inline]
pub unsafe fn transmute_immut<'a,T>(ptr: &'a mut T) -> &'a T {
    transmute(ptr)
}

/// Coerce a borrowed pointer to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
    transmute(ptr)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *mut T {
    transmute(ptr)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_immut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *T {
    transmute(ptr)
}

/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T {
    transmute(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_mut_lifetime<'a,S,T>(_ptr: &'a mut S, ptr: &mut T) -> &'a mut T {
    transmute_mut_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/****************************************************************************
 * Tests
 ****************************************************************************/

#[cfg(test)]
mod tests {
    use cast::{bump_box_refcount, transmute};
    use unstable::raw;

    #[test]
    fn test_transmute_copy() {
        assert_eq!(1u, unsafe { ::cast::transmute_copy(&1) });
    }

    #[test]
    fn test_bump_box_refcount() {
        unsafe {
            let box = @~"box box box";       // refcount 1
            bump_box_refcount(box);         // refcount 2
            let ptr: *int = transmute(box); // refcount 2
            let _box1: @~str = ::cast::transmute_copy(&ptr);
            let _box2: @~str = ::cast::transmute_copy(&ptr);
            assert!(*_box1 == ~"box box box");
            assert!(*_box2 == ~"box box box");
            // Will destroy _box1 and _box2. Without the bump, this would
            // use-after-free. With too many bumps, it would leak.
        }
    }

    #[test]
    fn test_transmute() {
        unsafe {
            let x = @100u8;
            let x: *raw::Box<u8> = transmute(x);
            assert!((*x).data == 100);
            let _x: @int = transmute(x);
        }
    }

    #[test]
    fn test_transmute2() {
        unsafe {
            assert_eq!(~[76u8], transmute(~"L"));
        }
    }
}
<commit_msg>auto merge of #10497 : thestinger/rust/cleanup, r=cmr<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Unsafe casting functions

use ptr::RawPtr;
use mem;
use unstable::intrinsics;
use ptr::copy_nonoverlapping_memory;

/// Casts the value at `src` to U. The two types must have the same length.
#[inline]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
    let mut dest: U = intrinsics::uninit();
    let dest_ptr: *mut u8 = transmute(&mut dest);
    let src_ptr: *u8 = transmute(src);
    copy_nonoverlapping_memory(dest_ptr, src_ptr, mem::size_of::<U>());
    dest
}

/**
 * Move a thing into the void
 *
 * The forget function will take ownership of the provided value but neglect
 * to run any required cleanup or memory-management operations on it. This
 * can be used for various acts of magick.
 */
#[inline]
pub unsafe fn forget<T>(thing: T) { intrinsics::forget(thing); }

/**
 * Force-increment the reference count on a shared box. If used
 * carelessly, this can leak the box.
 */
#[inline]
pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }

/**
 * Transform a value of one type into a value of another type.
 * Both types must have the same size and alignment.
 *
 * # Example
 *
 * ```rust
 * let v: &[u8] = transmute("L");
 * assert!(v == [76u8]);
 * ```
 */
#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
    intrinsics::transmute(thing)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }

/// Coerce a mutable reference to be immutable.
#[inline]
pub unsafe fn transmute_immut<'a,T>(ptr: &'a mut T) -> &'a T {
    transmute(ptr)
}

/// Coerce a borrowed pointer to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
    transmute(ptr)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *mut T {
    transmute(ptr)
}

/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_immut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *T {
    transmute(ptr)
}

/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
#[inline]
pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T {
    transmute(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_mut_lifetime<'a,S,T>(_ptr: &'a mut S, ptr: &mut T) -> &'a mut T {
    transmute_mut_region(ptr)
}

/// Transforms lifetime of the second pointer to match the first.
#[inline]
pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T {
    transmute_region(ptr)
}

/****************************************************************************
 * Tests
 ****************************************************************************/

#[cfg(test)]
mod tests {
    use cast::{bump_box_refcount, transmute};
    use unstable::raw;

    #[test]
    fn test_transmute_copy() {
        assert_eq!(1u, unsafe { ::cast::transmute_copy(&1) });
    }

    #[test]
    fn test_bump_box_refcount() {
        unsafe {
            let box = @~"box box box";       // refcount 1
            bump_box_refcount(box);         // refcount 2
            let ptr: *int = transmute(box); // refcount 2
            let _box1: @~str = ::cast::transmute_copy(&ptr);
            let _box2: @~str = ::cast::transmute_copy(&ptr);
            assert!(*_box1 == ~"box box box");
            assert!(*_box2 == ~"box box box");
            // Will destroy _box1 and _box2. Without the bump, this would
            // use-after-free. With too many bumps, it would leak.
        }
    }

    #[test]
    fn test_transmute() {
        unsafe {
            let x = @100u8;
            let x: *raw::Box<u8> = transmute(x);
            assert!((*x).data == 100);
            let _x: @int = transmute(x);
        }
    }

    #[test]
    fn test_transmute2() {
        unsafe {
            assert_eq!(~[76u8], transmute(~"L"));
        }
    }
}
<|endoftext|>


<commit_before>//! De-/serialization helpers for other ruma crates

pub mod can_be_empty;
mod canonical_json;
mod cow;
pub mod duration;
pub mod empty;
pub mod json_string;
mod raw;
pub mod single_element_seq;
mod strings;
pub mod test;
pub mod time;
pub mod urlencoded;

pub use can_be_empty::{is_empty, CanBeEmpty};
pub use canonical_json::{
    to_canonical_value, to_string as to_canonical_json_string, try_from_json_map,
    value::{CanonicalJsonValue, Object as CanonicalJsonObject},
    Error as CanonicalJsonError,
};
pub use cow::deserialize_cow_str;
pub use empty::vec_as_map_of_empty;
pub use raw::Raw;
pub use strings::{
    btreemap_int_or_string_to_int_values, empty_string_as_none, int_or_string_to_int,
};

/// Check whether a value is equal to its default value.
pub fn is_default<T: Default + PartialEq>(val: &T) -> bool {
    val == &T::default()
}

/// Simply returns `true`.
///
/// Useful for `#[serde(default = ...)]`.
pub fn default_true() -> bool {
    true
}

/// Simplfy dereferences the given bool.
///
/// Useful for `#[serde(skip_serializing_if = ...)]`
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn is_true(b: &bool) -> bool {
    *b
}

/// A type that can be sent to another party that understands the matrix protocol. If any of the
/// fields of `Self` don't implement serde's `Deserialize`, you can derive this trait to generate a
/// corresponding 'Incoming' type that supports deserialization. This is useful for things like
/// ruma_events' `EventResult` type. For more details, see the [derive macro's documentation][doc].
///
/// [doc]: derive.Outgoing.html
// TODO: Better explain how this trait relates to serde's traits
pub trait Outgoing {
    /// The 'Incoming' variant of `Self`.
    type Incoming;
}

// -- Everything below is macro-related --

pub use ruma_serde_macros::*;

/// This module is used to support the generated code from ruma-serde-macros.
/// It is not considered part of ruma-serde's public API.
#[doc(hidden)]
pub mod exports {
    pub use serde;
}
<commit_msg>Fix a typo<commit_after>//! De-/serialization helpers for other ruma crates

pub mod can_be_empty;
mod canonical_json;
mod cow;
pub mod duration;
pub mod empty;
pub mod json_string;
mod raw;
pub mod single_element_seq;
mod strings;
pub mod test;
pub mod time;
pub mod urlencoded;

pub use can_be_empty::{is_empty, CanBeEmpty};
pub use canonical_json::{
    to_canonical_value, to_string as to_canonical_json_string, try_from_json_map,
    value::{CanonicalJsonValue, Object as CanonicalJsonObject},
    Error as CanonicalJsonError,
};
pub use cow::deserialize_cow_str;
pub use empty::vec_as_map_of_empty;
pub use raw::Raw;
pub use strings::{
    btreemap_int_or_string_to_int_values, empty_string_as_none, int_or_string_to_int,
};

/// Check whether a value is equal to its default value.
pub fn is_default<T: Default + PartialEq>(val: &T) -> bool {
    val == &T::default()
}

/// Simply returns `true`.
///
/// Useful for `#[serde(default = ...)]`.
pub fn default_true() -> bool {
    true
}

/// Simply dereferences the given bool.
///
/// Useful for `#[serde(skip_serializing_if = ...)]`
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn is_true(b: &bool) -> bool {
    *b
}

/// A type that can be sent to another party that understands the matrix protocol. If any of the
/// fields of `Self` don't implement serde's `Deserialize`, you can derive this trait to generate a
/// corresponding 'Incoming' type that supports deserialization. This is useful for things like
/// ruma_events' `EventResult` type. For more details, see the [derive macro's documentation][doc].
///
/// [doc]: derive.Outgoing.html
// TODO: Better explain how this trait relates to serde's traits
pub trait Outgoing {
    /// The 'Incoming' variant of `Self`.
    type Incoming;
}

// -- Everything below is macro-related --

pub use ruma_serde_macros::*;

/// This module is used to support the generated code from ruma-serde-macros.
/// It is not considered part of ruma-serde's public API.
#[doc(hidden)]
pub mod exports {
    pub use serde;
}
<|endoftext|>


<commit_before>use super::RetransmissionTimerAlgorithm;
use std::collections::HashMap;
use std::cmp::{min, max};
use std::hash::Hash;
use std::sync::RwLock;

/// RFC6298をベースとした再送タイムアウト計算アルゴリズム
pub struct RFC6298BasedRTO<T: Hash + Eq> {
    state: RwLock<HashMap<T, State>>,
    min_rto: u32,
    clock_granularity: u32,
}

// RTOの初期値は1000[ms]
const DEFAULT_RTO: u32 = 1000;

// RTOの最大値は10秒 (RFC6298では60秒としてあるが，短めに設定)
const MAX_RTO: u32 = 10 * 1000;

struct State {
    srtt: i32,
    rttvar: i32,
    rto: u32,
}

impl<T: Sync + Send + Hash + Eq + Clone> RFC6298BasedRTO<T> {
    pub fn new(min_rto: u32, clock_granularity: u32) -> RFC6298BasedRTO<T> {
        RFC6298BasedRTO {
            state: RwLock::new(HashMap::new()),
            min_rto: min_rto,
            clock_granularity: clock_granularity,
        }
    }
}

impl<T: Sync + Send + Hash + Eq + Clone> RetransmissionTimerAlgorithm<T> for RFC6298BasedRTO<T> {
    fn add_sample(&self, key: &T, _: u64, rtt: u32, retransmit_cnt: u32) {
        if retransmit_cnt > 0 {
            return;
        }
        let mut locked = self.state.write().unwrap();
        match locked.get_mut(key) {
            Some(s) => {
                s.update(rtt, self.clock_granularity, self.min_rto);
                return;
            }
            _ => ()
        }
        locked.insert(key.clone(), State::new(rtt, self.clock_granularity));
    }

    fn get_rto(&self, key: &T, retransmit_count: u32) -> u32 {
        let rto = match self.state.read().unwrap().get(key) {
            Some(s) => s.rto,
            _ => DEFAULT_RTO,
        };
        if retransmit_count == 0 {
            rto
        } else {
            rto * 2u32.pow(retransmit_count)
        }
    }
}

impl State {
    fn new(rtt: u32, clock_granularity: u32) -> State {
        State {
            srtt: (rtt * 8) as i32,
            rttvar: (rtt * 2) as i32,
            rto: (rtt + max(clock_granularity, rtt * 2)) as u32,
        }
    }

    fn update(&mut self, rtt: u32, clock_granularity: u32, min_rto: u32) {
        let mut rtt = (rtt as i32) - (self.srtt >> 3);
        self.srtt += rtt;
        if rtt < 0 {
            rtt = -rtt;
        }
        self.rttvar -= (self.rttvar >> 2) - rtt;

        let rto = (self.srtt >> 3) as u32 + max(clock_granularity, self.rttvar as u32);
        self.rto = min(MAX_RTO, max(min_rto, rto));
    }
}

#[test]
fn test_rfc6298based() {
    let algo = RFC6298BasedRTO::<u32>::new(1, 50);
    assert_eq!(algo.get_rto(&0, 0), DEFAULT_RTO);
    algo.add_sample(&0, 0, 2000, 1);
    assert_eq!(algo.get_rto(&0, 0), DEFAULT_RTO); // Karn's algo
    algo.add_sample(&0, 0, 10, 0);
    assert_eq!(algo.get_rto(&0, 0), 60); // rtt + clock_granularity
    algo.add_sample(&0, 0, 20, 0);
    assert_eq!(algo.get_rto(&0, 0), 61); // rtt + clock_granularity
    algo.add_sample(&1, 0, 50, 0);
    assert_eq!(algo.get_rto(&1, 0), 150); // rtt + rttvar
    algo.add_sample(&1, 0, 100, 0);
    assert_eq!(algo.get_rto(&1, 0), 181); // rtt + rttvar

    assert_eq!(algo.get_rto(&2, 0), DEFAULT_RTO);
    assert_eq!(algo.get_rto(&2, 1), DEFAULT_RTO * 2);
    assert_eq!(algo.get_rto(&2, 2), DEFAULT_RTO * 4);
    assert_eq!(algo.get_rto(&2, 3), DEFAULT_RTO * 8);
    algo.add_sample(&2, 0, 10, 0);
    assert_eq!(algo.get_rto(&2, 0), 60);
    assert_eq!(algo.get_rto(&2, 1), 60 * 2);
    assert_eq!(algo.get_rto(&2, 2), 60 * 4);
    assert_eq!(algo.get_rto(&2, 3), 60 * 8);
}
<commit_msg>RTOを保存せずに必要なときに計算することにより，メモリ消費量を削減<commit_after>use super::RetransmissionTimerAlgorithm;
use std::collections::HashMap;
use std::cmp::{min, max};
use std::hash::Hash;
use std::sync::RwLock;

/// RFC6298をベースとした再送タイムアウト計算アルゴリズム
pub struct RFC6298BasedRTO<T: Hash + Eq> {
    state: RwLock<HashMap<T, State>>,
    min_rto: u32,
    clock_granularity: u32,
}

// RTOの初期値は1000[ms]
const DEFAULT_RTO: u32 = 1000;

// RTOの最大値は10秒 (RFC6298では60秒としてあるが，短めに設定)
const MAX_RTO: u32 = 10 * 1000;

struct State {
    srtt: i32,
    rttvar: i32,
}

impl<T: Sync + Send + Hash + Eq + Clone> RFC6298BasedRTO<T> {
    pub fn new(min_rto: u32, clock_granularity: u32) -> RFC6298BasedRTO<T> {
        RFC6298BasedRTO {
            state: RwLock::new(HashMap::new()),
            min_rto: min_rto,
            clock_granularity: clock_granularity,
        }
    }
}

impl<T: Sync + Send + Hash + Eq + Clone> RetransmissionTimerAlgorithm<T> for RFC6298BasedRTO<T> {
    fn add_sample(&self, key: &T, _: u64, rtt: u32, retransmit_cnt: u32) {
        if retransmit_cnt > 0 {
            return;
        }
        let mut locked = self.state.write().unwrap();
        match locked.get_mut(key) {
            Some(s) => {
                s.update(rtt);
                return;
            }
            _ => ()
        }
        locked.insert(key.clone(), State::new(rtt));
    }

    fn get_rto(&self, key: &T, retransmit_count: u32) -> u32 {
        let rto = match self.state.read().unwrap().get(key) {
            Some(s) => s.get_rto(self.clock_granularity, self.min_rto),
            _ => DEFAULT_RTO,
        };
        if retransmit_count == 0 {
            rto
        } else {
            rto * 2u32.pow(retransmit_count)
        }
    }
}

impl State {
    fn new(rtt: u32) -> State {
        State {
            srtt: (rtt * 8) as i32,
            rttvar: (rtt * 2) as i32,
        }
    }

    fn update(&mut self, rtt: u32) {
        let mut rtt = (rtt as i32) - (self.srtt >> 3);
        self.srtt += rtt;
        if rtt < 0 {
            rtt = -rtt;
        }
        self.rttvar -= (self.rttvar >> 2) - rtt;
    }

    fn get_rto(&self, clock_granularity: u32, min_rto: u32) -> u32 {
        let rto = (self.srtt >> 3) as u32 + max(clock_granularity, self.rttvar as u32);
        min(MAX_RTO, max(min_rto, rto))
    }
}

#[test]
fn test_rfc6298based() {
    let algo = RFC6298BasedRTO::<u32>::new(1, 50);
    assert_eq!(algo.get_rto(&0, 0), DEFAULT_RTO);
    algo.add_sample(&0, 0, 2000, 1);
    assert_eq!(algo.get_rto(&0, 0), DEFAULT_RTO); // Karn's algo
    algo.add_sample(&0, 0, 10, 0);
    assert_eq!(algo.get_rto(&0, 0), 60); // rtt + clock_granularity
    algo.add_sample(&0, 0, 20, 0);
    assert_eq!(algo.get_rto(&0, 0), 61); // rtt + clock_granularity
    algo.add_sample(&1, 0, 50, 0);
    assert_eq!(algo.get_rto(&1, 0), 150); // rtt + rttvar
    algo.add_sample(&1, 0, 100, 0);
    assert_eq!(algo.get_rto(&1, 0), 181); // rtt + rttvar

    assert_eq!(algo.get_rto(&2, 0), DEFAULT_RTO);
    assert_eq!(algo.get_rto(&2, 1), DEFAULT_RTO * 2);
    assert_eq!(algo.get_rto(&2, 2), DEFAULT_RTO * 4);
    assert_eq!(algo.get_rto(&2, 3), DEFAULT_RTO * 8);
    algo.add_sample(&2, 0, 10, 0);
    assert_eq!(algo.get_rto(&2, 0), 60);
    assert_eq!(algo.get_rto(&2, 1), 60 * 2);
    assert_eq!(algo.get_rto(&2, 2), 60 * 4);
    assert_eq!(algo.get_rto(&2, 3), 60 * 8);
}
<|endoftext|>


<commit_before>use nom::IResult;
use nom::HexDisplay;
use openvpn_parser::{parse_openvpn_udp,Payload};
use tls::TlsParser;

use rparser::{RParser,R_STATUS_OK,R_STATUS_FAIL};

pub struct OpenVPNUDPParser<'a> {
    _name: Option<&'a[u8]>,
    defrag_buf: Vec<u8>,

    tls_parser: TlsParser<'a>,
}

impl<'a> OpenVPNUDPParser<'a> {
    pub fn new(name: &'a[u8]) -> OpenVPNUDPParser<'a> {
        OpenVPNUDPParser{
            _name: Some(name),
            defrag_buf: Vec::new(),
            tls_parser: TlsParser::new(b"OpenVPN/TLS"),
        }
    }
}

impl<'a> RParser for OpenVPNUDPParser<'a> {
    fn parse(&mut self, i: &[u8], direction: u8) -> u32 {
        let mut cur_i = i;
        loop {
            match parse_openvpn_udp(cur_i) {
                IResult::Done(rem,r) => {
                    debug!("parse_openvpn_udp: {:?}", r);
                    if let Payload::Control(ref ctrl) = r.msg {
                        // XXX check number, and if packets needs to be reordered
                        self.defrag_buf.extend_from_slice(ctrl.payload);
                    }
                    if rem.len() == 0 { break; }
                    debug!("Remaining bytes: {}", rem.len());
                    cur_i = rem;
                },
                e @ _ => {
                    warn!("parse_openvpn_udp failed: {:?}", e);
                    warn!("input buffer:\n{}",i.to_hex(16));
                    return R_STATUS_FAIL;
                },
            }
        }
        if self.defrag_buf.len() > 0 {
            // inscpect TLS message
            debug!("TLS message:\n{}", self.defrag_buf.to_hex(16));
            self.tls_parser.parse_tcp_level(&self.defrag_buf, direction);
            self.defrag_buf.clear();
        }
        R_STATUS_OK
    }
}

pub fn openvpn_udp_probe(i: &[u8]) -> bool {
    if i.len() <= 20 { return false; }
    // XXX
    if let IResult::Done(_,_) = parse_openvpn_udp(i) { return true; }
    return false;
}

<commit_msg>Try to be more precise when detecting OpenVPN<commit_after>use nom::IResult;
use nom::HexDisplay;
use openvpn_parser::*;
use tls::TlsParser;

use rparser::{RParser,R_STATUS_OK,R_STATUS_FAIL};

pub struct OpenVPNUDPParser<'a> {
    _name: Option<&'a[u8]>,
    defrag_buf: Vec<u8>,

    tls_parser: TlsParser<'a>,
}

impl<'a> OpenVPNUDPParser<'a> {
    pub fn new(name: &'a[u8]) -> OpenVPNUDPParser<'a> {
        OpenVPNUDPParser{
            _name: Some(name),
            defrag_buf: Vec::new(),
            tls_parser: TlsParser::new(b"OpenVPN/TLS"),
        }
    }
}

impl<'a> RParser for OpenVPNUDPParser<'a> {
    fn parse(&mut self, i: &[u8], direction: u8) -> u32 {
        let mut cur_i = i;
        loop {
            match parse_openvpn_udp(cur_i) {
                IResult::Done(rem,r) => {
                    debug!("parse_openvpn_udp: {:?}", r);
                    if let Payload::Control(ref ctrl) = r.msg {
                        // XXX check number, and if packets needs to be reordered
                        self.defrag_buf.extend_from_slice(ctrl.payload);
                    }
                    if rem.len() == 0 { break; }
                    debug!("Remaining bytes: {}", rem.len());
                    cur_i = rem;
                },
                e @ _ => {
                    warn!("parse_openvpn_udp failed: {:?}", e);
                    warn!("input buffer:\n{}",i.to_hex(16));
                    return R_STATUS_FAIL;
                },
            }
        }
        if self.defrag_buf.len() > 0 {
            // inscpect TLS message
            debug!("TLS message:\n{}", self.defrag_buf.to_hex(16));
            self.tls_parser.parse_tcp_level(&self.defrag_buf, direction);
            self.defrag_buf.clear();
        }
        R_STATUS_OK
    }
}

pub fn openvpn_udp_probe(i: &[u8]) -> bool {
    if i.len() <= 20 { return false; }
    // XXX
    match parse_openvpn_udp(i) {
        IResult::Done(rem,pkt) => {
            println!("pkt: {:?}", pkt);
            println!("rem:\n{}", rem.to_hex(16));
            match pkt.hdr.opcode {
                P_CONTROL_V1 => {
                    if rem.len() > 3 && &rem[0..1] == &[0x16, 0x03] { true }
                    else { false }
                },
                P_ACK_V1 => {
                    if rem.is_empty() { true } else { false }
                },
                _ => false,
            }
        },
        _ => false,
    }
}

<|endoftext|>


<commit_before>use syntax::codemap;
use syntax::ast;
use syntax::ast::DefId;
use syntax::codemap::Pos;
use rustc::middle::ty;
use std::io::fs;
use std::path::posix;
use std::hash::Hash;
use collections::{HashMap,HashSet};
use std::slice;
use std::cmp;
use std::io;
use std::io::fs;
use codemaput::{ZIndexFilePos,ToZIndexFilePos};
use find_ast_node::{FNodeInfoMap,FNodeInfo,AstNode_};
use rfindctx::{RustFindCtx};
use crosscratemap::{CrossCrateMap,CrossCrateMapItem};
pub use super::NodeMaps;
use rsfind::MyOption;
use timer::Profiler;
use find_ast_node::*;
use rfindctx::*;

// build a call graph.
// we also want to build a graph of users of types - including types.

pub fn dump_functions(nmaps:&NodeMaps) {
	for (node_id, info) in nmaps.node_info_map.iter() {
		info.rf_as_fn_decl().map(|(ref item, fn_decl)|{
			println!("fn {}()", str_of_ident(item.ident));
		});
	}
//	fail!();
}

/// Options for callgraph generation
pub struct CG_Options {
	// TODO - when we have a solid IDE, we can stop Clike namespacing
	pub local_only:bool,
}
impl CG_Options {
	pub fn new()->CG_Options {
		CG_Options{local_only:true}
	}
}
/// Generate callgraph file.
/// Todo - seperate into callgraph iterator and file writer passing a closure..
type RefCCMItem<'a> =(DefId,&'a CrossCrateMapItem);
type SetOfItems<'a> =HashSet<RefCCMItem<'a>>;
type TraitMap<'a> =HashMap<DefId,TraitInfo<'a>>;

pub fn write_call_graph(nmaps:&NodeMaps, outdirname:&str, filename:&str,opts:&CG_Options) {

	let mut tg:TraitMap =HashMap::new();
//	gather_trait_graph(&tg, (xcm,nmaps), rf_get_root_node(nmaps.node_info_map));

	visit_call_graph( nmaps, |x,y|{});

	println!("Writing callgraph {} {}..",outdirname, filename);
	match (	fs::File::create(&posix::Path::new(outdirname+filename.to_owned()+~".txt")),
			fs::File::create(&posix::Path::new(outdirname+filename.to_owned()+~".dot")),
		)
	{
		(Ok(mut outf),Ok(mut dotf))=>
		{
			println!("writing callgraph file ..\n");
			dotf.write_line("digraph "+ filename +" {");
//			dotf.write_line("\toverlap=false; ");
//			dotf.write_line("\tnode[fontsize=8, width=0.2height=0.05] ");
			let mut fns_per_module:HashMap<&str,HashSet<RefCCMItem>> =HashMap::new();
			let mut all_calls:HashSet<(RefCCMItem,RefCCMItem)> =HashSet::new();
			dotf.write_line("\tnode [style=filled, color=lightgrey ]");

			// Traverse and collect..
			for (node_id, info) in nmaps.node_info_map.iter() {
				let mut calls:SetOfItems =HashSet::new();
				info.rf_as_fn_decl().map(
					|(ref item, fn_decl)|{
						let fn_defid=DefId{krate:0,node:*node_id};
						let xcmi=nmaps.rf_find_source(&fn_defid).unwrap();

						fns_per_module.insert_or_update_with(
							xcmi.file_name.as_slice(),	// key,
							HashSet::new(),	// new value if not found,
							|k,v|{v.insert((fn_defid, xcmi));} // update the value if found.
						);
						let caller_str = str_of_ident(item.ident);
						outf.write_line(format!("fn {}() {}:{}", caller_str, xcmi.file_name,xcmi.line+1));
						gather_call_graph_rec(&mut calls, nmaps,  *node_id);

						for &(ref defid,ref call_item) in calls.iter() {
							outf.write_line(format!("\tcalls {}() {}:{}",call_item.item_name, call_item.file_name, call_item.line+1));
							// TODO: actually 'local-only' should gather external nodes into one-
							// i.e. show dependancy on module/crate.

							if !(opts.local_only && defid.krate!=0) {
								all_calls.insert( ((fn_defid,xcmi), (*defid, *call_item)) );
							}
						}
					}
				);
			}
			// Write out a cluster for all the functions in a particular sourcefile.
			// TODO - should be able to recursively cluster directories for this..
			for (&modname,items) in fns_per_module.iter() {
//				let modstr=::std::str::from_chars(modname.chars().map(|x|if x=='/'{'_'}else{x}));
				let modstr:~str=modname.chars().map(|x|match x{'/'|'.'=>'_',_=>x}).collect();
				if items.len()==0{ continue;}
				if modstr.chars().nth(0)==Some('<') {continue;} // things like <std macros>
				dotf.write_line("\tsubgraph cluster_"+modstr+"{");
				dotf.write_line("\t\tlabel=\""+modname+"\"");
				dotf.write_line("\t\tstyle=filled");
				dotf.write_line("\t\tcolor=darkgrey");
				for &(defid,xcmi) in items.iter() {
					let url_name= xcmi.file_name+".html#"+(xcmi.line+1).to_str();
					dotf.write_line("\t\t"+fn_to_dotfile_symbol((defid,xcmi)) + "["+
						if is_main((defid,xcmi)){"style=filled,fontcolor=white color=blue, "}else{" "/*"style=filled, color=lightgrey "*/}+
						"label=\""+xcmi.item_name+"()\" URL=\""+ url_name  + "\"];");
				}
				dotf.write_line("\t}");
			}
			// Write out all the calls..
			for &(f1,f2) in all_calls.iter() {
				let fstr1=fn_to_dotfile_symbol(f1);
				let fstr2=fn_to_dotfile_symbol(f2);
				if fstr1.len()>0 && fstr2.len()>0 {

					dotf.write_line("\t"+ fstr1 +" -> "+ fstr2 + "[len=4.0]"
//						if is_main(f1)|| is_main(f2) {" [len=10.0];"} else {" [len=4.0];"}
					);
				}
			}

			fn fn_to_dotfile_symbol((def_id,xcmi):RefCCMItem)-> ~str {
				// TODO: this should be the symbols' qualified module pathname
				// its only coincidentally correlated with the filename+symbol most of the time.
				let pathname:~str=xcmi.file_name.chars().map(|x|match x{'/'|'.'=>'_',_=>x}).collect();
				pathname +"_"+xcmi.item_name
			}
			fn is_main((def_id,xcmi):RefCCMItem)->bool{
				xcmi.item_name.as_slice()=="main"
			}

//			fn rank_within(items:&Set<RefCCMItem>, &Vec<(RefCCMItem,RefCCMItem>

			dotf.write_line("}");
		}
		_ => println!("can't write callgraph {}", filename),
	}
//	fail!();
}

/// calls closure for each caller-callee pair encountered in the whole crates' static callgraph, including both function and method calls.
/// does so by traversing all the nodes, finding any that are function declarations, then calls a gather function that traverses the bodies looking for calls & method calls.
/// requires populated CrossCrateMap and NodeMaps

//static mut dbg1:HashSet<NodeId> =HashSet::new()
static debug_callgraph:bool=false;
pub fn visit_call_graph<'a>(nmaps:&'a NodeMaps, f:|caller:RefCCMItem, callee:RefCCMItem|)
{
//	let mut dbg_calls_found_recursively=0;
	for (node_id, info) in nmaps.node_info_map.iter() {
		info.rf_as_fn_decl().map(
			|(ref fn_item, fn_decl)|{
				let caller_defid=ast::DefId{krate:0,node:*node_id};
				let caller_ccmitem=nmaps.rf_find_source(&caller_defid).unwrap();

				let mut calls:SetOfItems=HashSet::new();
				gather_call_graph_rec(&mut calls, nmaps,  *node_id);

				if debug_callgraph{
					println!("{}() {}:{}",caller_ccmitem.item_name, caller_ccmitem.file_name, caller_ccmitem.line+1);
				}
				for &(ref defid,call_ccmitem) in calls.iter() {
					if debug_callgraph{
						println!("\tcalls  {}() {}:{}",call_ccmitem.item_name, call_ccmitem.file_name, call_ccmitem.line+1);
					}
					f((caller_defid, caller_ccmitem), (*defid,call_ccmitem));
				}
			}
		);
	}
}

fn gather_call_graph_rec<'s>(calls:&mut SetOfItems<'s>,nmaps:&'s NodeMaps, node:ast::NodeId)
{
	let node=nmaps.node_info_map.find(&node).unwrap();

	// todo 'for child in iter_children(nmaps,node)' {
//	for &child_id in node.children.iter() {
	node.rf_visit_children(
		nmaps.node_info_map,
		|child_id, child_node|{
			gather_call_graph_rec(calls, nmaps, child_id);
			let target=match child_node.rf_node() {
				// get the callee .. caution, its the fncalls's 'callee_expr'.id, not the caller node itself..
				astnode_expr(expr)=>{
					match expr.node {
						ast::ExprCall( ref call_expr,ref args)=>{
							nmaps.jump_def_map.find(&call_expr.id)
						},
						ast::ExprMethodCall(ref ident,ref typeargs,ref args)=>{
							nmaps.jump_def_map.find(&child_id)
						},
						_=>{None}
					}
				},
				_=>{None},
			};
			match target{
				None=>{},
				Some(x)=>{
					match nmaps.rf_find_source(x) {
						Some(xcm_item)=>{calls.insert((*x,xcm_item));},
						None=>{/*println!("call with no source \n", )*/}
					}
				}
			}
		}
	);
}

struct TraitInfo<'a> {
	pub ti_defid: RefCCMItem<'a>,
	pub ti_name:~str,
	pub ti_module:DefId,
	pub ti_inherits:HashSet<DefId>,
	pub ti_functions:HashSet<DefId>,
}

fn gather_trait_graph_rec<'a>(tg:&mut HashMap<DefId,TraitInfo<'a>>, nmaps:&'a NodeMaps, node_id:ast::NodeId)
{
	// todo 'for child in iter_children(nmaps,node)' {
	let node=nmaps.node_info_map.find(&node_id).unwrap();
	node.rf_visit_children(
		nmaps.node_info_map,
		|child_id, child_node| {
//	for &child_id in node.children.iter() {
//			let child_node = nmaps.node_info_map.find(&child_id).unwrap();

			match child_node.rf_node() {
				// is it in decl, or item?!
				astnode_item(item)=> {
					match item.node {
						// to escape the pyramid of doom, we want to pass ::ItemTrait, but its not a type itself :( we hope rust gets this addition
						ast::ItemTrait(ref g,ref tr, ref tm)=>{
							gather_trait_graph_sub((g,tr,tm),tg,nmaps,child_node);
						},
						_=>{}
					}
				}
				_=>{
				}
			}
			gather_trait_graph_rec(tg, nmaps, child_id);
		}
	);
}

// we hope they will in future allow inference between functions in the same module-
// easier to break up and refactor.
// the only reason we're writing this function is to reduce indentation above.
fn gather_trait_graph_sub<'a>(
		(g,tr,rm):(&ast::Generics,&Vec<ast::TraitRef>,&Vec<ast::TraitMethod>),
		tg:&mut HashMap<DefId, TraitInfo<'a>>,
		nmaps:&'a NodeMaps,
		node:&FNodeInfo)
{
	println!("trait {}\n", str_of_opt_ident(node.rf_get_ident()));
}

// TODO: populate this
pub struct FunctionUseGraph {
	pub fn_per_type: HashMap<DefId, DefId>,
	pub type_per_fn: HashMap<DefId, DefId>,
	pub common_pairs: HashSet<(DefId,DefId)>
}

<commit_msg>cleanup callgraph generation code<commit_after>use syntax::codemap;
use syntax::ast;
use syntax::ast::DefId;
use syntax::codemap::Pos;
use rustc::middle::ty;
use std::io::fs;
use std::path::posix;
use std::hash::Hash;
use collections::{HashMap,HashSet};
use std::slice;
use std::cmp;
use std::io;
use std::io::fs;
use codemaput::{ZIndexFilePos,ToZIndexFilePos};
use find_ast_node::{FNodeInfoMap,FNodeInfo,AstNode_};
use rfindctx::{RustFindCtx};
use crosscratemap::{CrossCrateMap,CrossCrateMapItem};
pub use super::NodeMaps;
use rsfind::MyOption;
use timer::Profiler;
use find_ast_node::*;
use rfindctx::*;

// build a call graph.
// we also want to build a graph of users of types - including types.

pub fn dump_functions(nmaps:&NodeMaps) {
	for (node_id, info) in nmaps.node_info_map.iter() {
		info.rf_as_fn_decl().map(|(ref item, fn_decl)|{
			println!("fn {}()", str_of_ident(item.ident));
		});
	}
//	fail!();
}

/// Options for callgraph generation
pub struct CG_Options {
	// TODO - when we have a solid IDE, we can stop Clike namespacing
	pub local_only:bool,
}
impl CG_Options {
	pub fn new()->CG_Options {
		CG_Options{local_only:true}
	}
}
/// Generate callgraph file.
/// Todo - seperate into callgraph iterator and file writer passing a closure..
type RefCCMItem<'a> =(DefId,&'a CrossCrateMapItem);
type SetOfItems<'a> =HashSet<RefCCMItem<'a>>;
type TraitMap<'a> =HashMap<DefId,TraitInfo<'a>>;

// TODO: Use mangled symbols for the nodes.
pub fn write_call_graph<'a>(nmaps:&'a NodeMaps, outdirname:&str, filename:&str,opts:&CG_Options) {

	let mut tg:TraitMap =HashMap::new();
//	gather_trait_graph(&tg, (xcm,nmaps), rf_get_root_node(nmaps.node_info_map));

	visit_call_graph( nmaps, |x,y|{});

	println!("Writing callgraph {} {}..",outdirname, filename);
	match fs::File::create(&posix::Path::new(outdirname+filename.to_owned()+~".dot"),
	{
		Ok(mut dotf)=>
		{
			println!("writing callgraph file ..\n");
			dotf.write_line("digraph "+ filename +" {");
			let mut fns_per_module:HashMap<&str,HashSet<RefCCMItem>> =HashMap::new();
			let mut all_calls:HashSet<(RefCCMItem<'a>,RefCCMItem<'a>)> =HashSet::new();
			dotf.write_line("\tnode [style=filled, color=lightgrey ]");

			visit_call_graph(nmaps, // We miss do notation :(
				|caller,callee| {
					for x in [caller,callee].iter() {
						fns_per_module.insert_or_update_with(x.val1().file_name.as_slice(), HashSet::new(), |k,v|{v.insert(*x);});
					}

					if !(opts.local_only && callee.val0().krate!=0) {
						all_calls.insert( (caller, callee) );
					}
				}
			);

			// Write out a cluster for all the functions in a particular sourcefile.
			// TODO - should be able to recursively cluster directories for this..
			// TODO: Generalize to modules.
			for (&modname,items) in fns_per_module.iter() {
//				let modstr=::std::str::from_chars(modname.chars().map(|x|if x=='/'{'_'}else{x}));
				let modstr:~str=modname.chars().map(|x|match x{'/'|'.'=>'_',_=>x}).collect();
				if items.len()==0{ continue;}
				if modstr.chars().nth(0)==Some('<') {continue;} // things like <std macros>
				dotf.write_line("\tsubgraph cluster_"+modstr+"{");
				dotf.write_line("\t\tlabel=\""+modname+"\"");
				dotf.write_line("\t\tstyle=filled");
				dotf.write_line("\t\tcolor=darkgrey");
				for &(defid,xcmi) in items.iter() {
					let url_name= xcmi.file_name+".html#"+(xcmi.line+1).to_str();
					dotf.write_line("\t\t"+fn_to_dotfile_symbol((defid,xcmi)) + "["+
						if is_main((defid,xcmi)){"style=filled,fontcolor=white color=blue, "}else{" "/*"style=filled, color=lightgrey "*/}+
						"label=\""+xcmi.item_name+"()\" URL=\""+ url_name  + "\"];");
				}
				dotf.write_line("\t}");
			}
			// Write out all the calls..
			dotf.write_line("edge [len=4.0];");
			for &(f1,f2) in all_calls.iter() {
				let fstr1=fn_to_dotfile_symbol(f1);
				let fstr2=fn_to_dotfile_symbol(f2);
				if fstr1.len()>0 && fstr2.len()>0 {

					dotf.write_line("\t"+ fstr1 +" -> "+ fstr2
//						if is_main(f1)|| is_main(f2) {" [len=10.0];"} else {" [len=4.0];"}
					);
				}
			}

			fn fn_to_dotfile_symbol((def_id,xcmi):RefCCMItem)-> ~str {
				// TODO: this should be the symbols' qualified module pathname
				// its only coincidentally correlated with the filename+symbol most of the time.
				let pathname:~str=xcmi.file_name.chars().map(|x|match x{'/'|'.'=>'_',_=>x}).collect();
				pathname +"_"+xcmi.item_name
			}
			fn is_main((def_id,xcmi):RefCCMItem)->bool{
				xcmi.item_name.as_slice()=="main"
			}

//			fn rank_within(items:&Set<RefCCMItem>, &Vec<(RefCCMItem,RefCCMItem>
			dotf.write_line("}");
		}
		_ => println!("can't write callgraph {}", filename),
	}
}

/// calls closure for each caller-callee pair encountered in the whole crates' static callgraph, including both function and method calls.
/// does so by traversing all the nodes, finding any that are function declarations, then calls a gather function that traverses the bodies looking for calls & method calls.
/// requires populated CrossCrateMap and NodeMaps

//static mut dbg1:HashSet<NodeId> =HashSet::new()
static debug_callgraph:bool=false;
pub fn visit_call_graph<'a>(nmaps:&'a NodeMaps, f:|caller:RefCCMItem<'a>, callee:RefCCMItem<'a>|)
{
//	let mut dbg_calls_found_recursively=0;
	for (node_id, info) in nmaps.node_info_map.iter() {
		info.rf_as_fn_decl().map(
			|(ref fn_item, fn_decl)|{
				let caller_defid=ast::DefId{krate:0,node:*node_id};
				let caller_ccmitem=nmaps.rf_find_source(&caller_defid).unwrap();

				let mut calls:SetOfItems=HashSet::new();
				gather_call_graph_rec(&mut calls, nmaps,  *node_id);

				if debug_callgraph{
					println!("{}() {}:{}",caller_ccmitem.item_name, caller_ccmitem.file_name, caller_ccmitem.line+1);
				}
				for &(ref defid,call_ccmitem) in calls.iter() {
					if debug_callgraph{
						println!("\tcalls  {}() {}:{}",call_ccmitem.item_name, call_ccmitem.file_name, call_ccmitem.line+1);
					}
					f((caller_defid, caller_ccmitem), (*defid,call_ccmitem));
				}
			}
		);
	}
}

fn gather_call_graph_rec<'s>(calls:&mut SetOfItems<'s>,nmaps:&'s NodeMaps, node:ast::NodeId)
{
	let node=nmaps.node_info_map.find(&node).unwrap();

	// todo 'for child in iter_children(nmaps,node)' {
//	for &child_id in node.children.iter() {
	node.rf_visit_children(
		nmaps.node_info_map,
		|child_id, child_node|{
			gather_call_graph_rec(calls, nmaps, child_id);
			let target=match child_node.rf_node() {
				// get the callee .. caution, its the fncalls's 'callee_expr'.id, not the caller node itself..
				astnode_expr(expr)=>{
					match expr.node {
						ast::ExprCall( ref call_expr,ref args)=>{
							nmaps.jump_def_map.find(&call_expr.id)
						},
						ast::ExprMethodCall(ref ident,ref typeargs,ref args)=>{
							nmaps.jump_def_map.find(&child_id)
						},
						_=>{None}
					}
				},
				_=>{None},
			};
			match target{
				None=>{},
				Some(x)=>{
					match nmaps.rf_find_source(x) {
						Some(xcm_item)=>{calls.insert((*x,xcm_item));},
						None=>{/*println!("call with no source \n", )*/}
					}
				}
			}
		}
	);
}

struct TraitInfo<'a> {
	pub ti_defid: RefCCMItem<'a>,
	pub ti_name:~str,
	pub ti_module:DefId,
	pub ti_inherits:HashSet<DefId>,
	pub ti_functions:HashSet<DefId>,
}

fn gather_trait_graph_rec<'a>(tg:&mut HashMap<DefId,TraitInfo<'a>>, nmaps:&'a NodeMaps, node_id:ast::NodeId)
{
	// todo 'for child in iter_children(nmaps,node)' {
	let node=nmaps.node_info_map.find(&node_id).unwrap();
	node.rf_visit_children(
		nmaps.node_info_map,
		|child_id, child_node| {
//	for &child_id in node.children.iter() {
//			let child_node = nmaps.node_info_map.find(&child_id).unwrap();

			match child_node.rf_node() {
				// is it in decl, or item?!
				astnode_item(item)=> {
					match item.node {
						// to escape the pyramid of doom, we want to pass ::ItemTrait, but its not a type itself :( we hope rust gets this addition
						ast::ItemTrait(ref g,ref tr, ref tm)=>{
							gather_trait_graph_sub((g,tr,tm),tg,nmaps,child_node);
						},
						_=>{}
					}
				}
				_=>{
				}
			}
			gather_trait_graph_rec(tg, nmaps, child_id);
		}
	);
}

// we hope they will in future allow inference between functions in the same module-
// easier to break up and refactor.
// the only reason we're writing this function is to reduce indentation above.
fn gather_trait_graph_sub<'a>(
		(g,tr,rm):(&ast::Generics,&Vec<ast::TraitRef>,&Vec<ast::TraitMethod>),
		tg:&mut HashMap<DefId, TraitInfo<'a>>,
		nmaps:&'a NodeMaps,
		node:&FNodeInfo)
{
	println!("trait {}\n", str_of_opt_ident(node.rf_get_ident()));
}

// TODO: populate this
pub struct FunctionUseGraph {
	pub fn_per_type: HashMap<DefId, DefId>,
	pub type_per_fn: HashMap<DefId, DefId>,
	pub common_pairs: HashSet<(DefId,DefId)>
}

<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;

use cranelift::codegen::entity::EntityMap;
use cranelift::codegen::write::{FuncWriter, PlainWriter};

use crate::prelude::*;

pub struct CommentWriter(pub HashMap<Inst, String>);

impl FuncWriter for CommentWriter {
    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &EntityMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.0.get(&inst) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }

    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        PlainWriter.write_preamble(w, func, reg_info)
    }
}

impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
    pub fn add_global_comment<'s, S: Into<Cow<'s, str>>>(&mut self, comment: S) {
        self.add_comment(self.top_nop.expect("fx.top_nop not yet set"), comment)
    }

    pub fn add_comment<'s, S: Into<Cow<'s, str>>>(&mut self, inst: Inst, comment: S) {
        use std::collections::hash_map::Entry;
        match self.comments.entry(inst) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.into().as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into().into_owned());
            }
        }
    }
}
<commit_msg>EntityMap got renamed to SecondaryMap<commit_after>use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;

use cranelift::codegen::entity::SecondaryMap;
use cranelift::codegen::write::{FuncWriter, PlainWriter};

use crate::prelude::*;

pub struct CommentWriter(pub HashMap<Inst, String>);

impl FuncWriter for CommentWriter {
    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &SecondaryMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.0.get(&inst) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }

    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        PlainWriter.write_preamble(w, func, reg_info)
    }
}

impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
    pub fn add_global_comment<'s, S: Into<Cow<'s, str>>>(&mut self, comment: S) {
        self.add_comment(self.top_nop.expect("fx.top_nop not yet set"), comment)
    }

    pub fn add_comment<'s, S: Into<Cow<'s, str>>>(&mut self, inst: Inst, comment: S) {
        use std::collections::hash_map::Entry;
        match self.comments.entry(inst) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.into().as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into().into_owned());
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Get project by id.
//!
//! https://docs.gitlab.com/ce/api/projects.html#get-single-project
//!
//! # Get single project
//!
//! Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME, which is owned by
//! the authenticated user.
//! If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded,
//! eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`).
//!
//! ```text
//! GET /projects/:id
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id` | integer/string | yes | The ID or NAMESPACE/PROJECT_NAME of the project |
<commit_msg>Use `ID` instead of `:id`<commit_after>//! Get project by id.
//!
//! https://docs.gitlab.com/ce/api/projects.html#get-single-project
//!
//! # Get single project
//!
//! Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME, which is owned by
//! the authenticated user.
//! If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded,
//! eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`).
//!
//! ```text
//! GET /projects/ID
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `id` | integer/string | yes | The ID or NAMESPACE/PROJECT_NAME of the project |
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ast;
use syntax::source_map::Span;
use syntax::visit::FnKind;
use syntax_pos::BytePos;

use crate::utils::{match_path_ast, snippet_opt, span_lint_and_then};

declare_clippy_lint! {
    /// **What it does:** Checks for return statements at the end of a block.
    ///
    /// **Why is this bad?** Removing the `return` and semicolon will make the code
    /// more rusty.
    ///
    /// **Known problems:** If the computation returning the value borrows a local
    /// variable, removing the `return` may run afoul of the borrow checker.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    /// simplify to
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    pub NEEDLESS_RETURN,
    style,
    "using a return statement like `return expr;` where an expression would suffice"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `let`-bindings, which are subsequently
    /// returned.
    ///
    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
    /// more rusty.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo() -> String {
    ///     let x = String::new();
    ///     x
    /// }
    /// ```
    /// instead, use
    /// ```
    /// fn foo() -> String {
    ///     String::new()
    /// }
    /// ```
    pub LET_AND_RETURN,
    style,
    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
}

declare_clippy_lint! {
    /// **What it does:** Checks for unit (`()`) expressions that can be removed.
    ///
    /// **Why is this bad?** Such expressions add no value, but can make the code
    /// less readable. Depending on formatting they can make a `break` or `return`
    /// statement look like a function call.
    ///
    /// **Known problems:** The lint currently misses unit return types in types,
    /// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`.
    ///
    /// **Example:**
    /// ```rust
    /// fn return_unit() -> () {
    ///     ()
    /// }
    /// ```
    pub UNUSED_UNIT,
    style,
    "needless unit expression"
}

#[derive(PartialEq, Eq, Copy, Clone)]
enum RetReplacement {
    Empty,
    Block,
}

declare_lint_pass!(Return => [NEEDLESS_RETURN, LET_AND_RETURN, UNUSED_UNIT]);

impl Return {
    // Check the final stmt or expr in a block for unnecessary return.
    fn check_block_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        if let Some(stmt) = block.stmts.last() {
            match stmt.node {
                ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
                    self.check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
                },
                _ => (),
            }
        }
    }

    // Check a the final expression in a block if it's a return.
    fn check_final_expr(
        &mut self,
        cx: &EarlyContext<'_>,
        expr: &ast::Expr,
        span: Option<Span>,
        replacement: RetReplacement,
    ) {
        match expr.node {
            // simple return is always "bad"
            ast::ExprKind::Ret(ref inner) => {
                // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
                if !expr.attrs.iter().any(attr_is_cfg) {
                    self.emit_return_lint(
                        cx,
                        span.expect("`else return` is not possible"),
                        inner.as_ref().map(|i| i.span),
                        replacement,
                    );
                }
            },
            // a whole block? check it!
            ast::ExprKind::Block(ref block, _) => {
                self.check_block_return(cx, block);
            },
            // an if/if let expr, check both exprs
            // note, if without else is going to be a type checking error anyways
            // (except for unit type functions) so we don't match it
            ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => {
                self.check_block_return(cx, ifblock);
                self.check_final_expr(cx, elsexpr, None, RetReplacement::Empty);
            },
            // a match expr, check all arms
            ast::ExprKind::Match(_, ref arms) => {
                for arm in arms {
                    self.check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
                }
            },
            _ => (),
        }
    }

    fn emit_return_lint(
        &mut self,
        cx: &EarlyContext<'_>,
        ret_span: Span,
        inner_span: Option<Span>,
        replacement: RetReplacement,
    ) {
        match inner_span {
            Some(inner_span) => {
                if in_external_macro(cx.sess(), inner_span) || inner_span.from_expansion() {
                    return;
                }

                span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| {
                    if let Some(snippet) = snippet_opt(cx, inner_span) {
                        db.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
                    }
                })
            },
            None => match replacement {
                RetReplacement::Empty => {
                    span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| {
                        db.span_suggestion(
                            ret_span,
                            "remove `return`",
                            String::new(),
                            Applicability::MachineApplicable,
                        );
                    });
                },
                RetReplacement::Block => {
                    span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| {
                        db.span_suggestion(
                            ret_span,
                            "replace `return` with an empty block",
                            "{}".to_string(),
                            Applicability::MachineApplicable,
                        );
                    });
                },
            },
        }
    }

    // Check for "let x = EXPR; x"
    fn check_let_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        let mut it = block.stmts.iter();

        // we need both a let-binding stmt and an expr
        if_chain! {
            if let Some(retexpr) = it.next_back();
            if let ast::StmtKind::Expr(ref retexpr) = retexpr.node;
            if let Some(stmt) = it.next_back();
            if let ast::StmtKind::Local(ref local) = stmt.node;
            // don't lint in the presence of type inference
            if local.ty.is_none();
            if local.attrs.is_empty();
            if let Some(ref initexpr) = local.init;
            if let ast::PatKind::Ident(_, ident, _) = local.pat.node;
            if let ast::ExprKind::Path(_, ref path) = retexpr.node;
            if match_path_ast(path, &[&*ident.name.as_str()]);
            if !in_external_macro(cx.sess(), initexpr.span);
            then {
                span_lint_and_then(
                    cx,
                    LET_AND_RETURN,
                    retexpr.span,
                    "returning the result of a let binding from a block",
                    |err| {
                        err.span_label(local.span, "unnecessary let binding");

                        if let Some(snippet) = snippet_opt(cx, initexpr.span) {
                            err.multipart_suggestion(
                                "return the expression directly",
                                vec![
                                    (local.span, String::new()),
                                    (retexpr.span, snippet),
                                ],
                                Applicability::MachineApplicable,
                            );
                        } else {
                            err.span_help(initexpr.span, "this expression can be directly returned");
                        }
                    },
                );
            }
        }
    }
}

impl EarlyLintPass for Return {
    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, decl: &ast::FnDecl, span: Span, _: ast::NodeId) {
        match kind {
            FnKind::ItemFn(.., block) | FnKind::Method(.., block) => self.check_block_return(cx, block),
            FnKind::Closure(body) => self.check_final_expr(cx, body, Some(body.span), RetReplacement::Empty),
        }
        if_chain! {
            if let ast::FunctionRetTy::Ty(ref ty) = decl.output;
            if let ast::TyKind::Tup(ref vals) = ty.node;
            if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
            then {
                let (rspan, appl) = if let Ok(fn_source) =
                        cx.sess().source_map()
                                 .span_to_snippet(span.with_hi(ty.span.hi())) {
                    if let Some(rpos) = fn_source.rfind("->") {
                        #[allow(clippy::cast_possible_truncation)]
                        (ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
                            Applicability::MachineApplicable)
                    } else {
                        (ty.span, Applicability::MaybeIncorrect)
                    }
                } else {
                    (ty.span, Applicability::MaybeIncorrect)
                };
                span_lint_and_then(cx, UNUSED_UNIT, rspan, "unneeded unit return type", |db| {
                    db.span_suggestion(
                        rspan,
                        "remove the `-> ()`",
                        String::new(),
                        appl,
                    );
                });
            }
        }
    }

    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        self.check_let_return(cx, block);
        if_chain! {
            if let Some(ref stmt) = block.stmts.last();
            if let ast::StmtKind::Expr(ref expr) = stmt.node;
            if is_unit_expr(expr) && !stmt.span.from_expansion();
            then {
                let sp = expr.span;
                span_lint_and_then(cx, UNUSED_UNIT, sp, "unneeded unit expression", |db| {
                    db.span_suggestion(
                        sp,
                        "remove the final `()`",
                        String::new(),
                        Applicability::MachineApplicable,
                    );
                });
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
        match e.node {
            ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
                if is_unit_expr(expr) && !expr.span.from_expansion() {
                    span_lint_and_then(cx, UNUSED_UNIT, expr.span, "unneeded `()`", |db| {
                        db.span_suggestion(
                            expr.span,
                            "remove the `()`",
                            String::new(),
                            Applicability::MachineApplicable,
                        );
                    });
                }
            },
            _ => (),
        }
    }
}

fn attr_is_cfg(attr: &ast::Attribute) -> bool {
    attr.meta_item_list().is_some() && attr.check_name(sym!(cfg))
}

// get the def site
fn get_def(span: Span) -> Option<Span> {
    if span.from_expansion() {
        Some(span.ctxt().outer_expn_data().def_site)
    } else {
        None
    }
}

// is this expr a `()` unit?
fn is_unit_expr(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Tup(ref vals) = expr.node {
        vals.is_empty()
    } else {
        false
    }
}
<commit_msg>Fix let_and_return lint<commit_after>use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ast;
use syntax::source_map::Span;
use syntax::visit::FnKind;
use syntax_pos::BytePos;

use crate::utils::{match_path_ast, snippet_opt, span_lint_and_then};

declare_clippy_lint! {
    /// **What it does:** Checks for return statements at the end of a block.
    ///
    /// **Why is this bad?** Removing the `return` and semicolon will make the code
    /// more rusty.
    ///
    /// **Known problems:** If the computation returning the value borrows a local
    /// variable, removing the `return` may run afoul of the borrow checker.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    /// simplify to
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    pub NEEDLESS_RETURN,
    style,
    "using a return statement like `return expr;` where an expression would suffice"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `let`-bindings, which are subsequently
    /// returned.
    ///
    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
    /// more rusty.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo() -> String {
    ///     let x = String::new();
    ///     x
    /// }
    /// ```
    /// instead, use
    /// ```
    /// fn foo() -> String {
    ///     String::new()
    /// }
    /// ```
    pub LET_AND_RETURN,
    style,
    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
}

declare_clippy_lint! {
    /// **What it does:** Checks for unit (`()`) expressions that can be removed.
    ///
    /// **Why is this bad?** Such expressions add no value, but can make the code
    /// less readable. Depending on formatting they can make a `break` or `return`
    /// statement look like a function call.
    ///
    /// **Known problems:** The lint currently misses unit return types in types,
    /// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`.
    ///
    /// **Example:**
    /// ```rust
    /// fn return_unit() -> () {
    ///     ()
    /// }
    /// ```
    pub UNUSED_UNIT,
    style,
    "needless unit expression"
}

#[derive(PartialEq, Eq, Copy, Clone)]
enum RetReplacement {
    Empty,
    Block,
}

declare_lint_pass!(Return => [NEEDLESS_RETURN, LET_AND_RETURN, UNUSED_UNIT]);

impl Return {
    // Check the final stmt or expr in a block for unnecessary return.
    fn check_block_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        if let Some(stmt) = block.stmts.last() {
            match stmt.node {
                ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
                    self.check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
                },
                _ => (),
            }
        }
    }

    // Check a the final expression in a block if it's a return.
    fn check_final_expr(
        &mut self,
        cx: &EarlyContext<'_>,
        expr: &ast::Expr,
        span: Option<Span>,
        replacement: RetReplacement,
    ) {
        match expr.node {
            // simple return is always "bad"
            ast::ExprKind::Ret(ref inner) => {
                // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
                if !expr.attrs.iter().any(attr_is_cfg) {
                    self.emit_return_lint(
                        cx,
                        span.expect("`else return` is not possible"),
                        inner.as_ref().map(|i| i.span),
                        replacement,
                    );
                }
            },
            // a whole block? check it!
            ast::ExprKind::Block(ref block, _) => {
                self.check_block_return(cx, block);
            },
            // an if/if let expr, check both exprs
            // note, if without else is going to be a type checking error anyways
            // (except for unit type functions) so we don't match it
            ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => {
                self.check_block_return(cx, ifblock);
                self.check_final_expr(cx, elsexpr, None, RetReplacement::Empty);
            },
            // a match expr, check all arms
            ast::ExprKind::Match(_, ref arms) => {
                for arm in arms {
                    self.check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
                }
            },
            _ => (),
        }
    }

    fn emit_return_lint(
        &mut self,
        cx: &EarlyContext<'_>,
        ret_span: Span,
        inner_span: Option<Span>,
        replacement: RetReplacement,
    ) {
        match inner_span {
            Some(inner_span) => {
                if in_external_macro(cx.sess(), inner_span) || inner_span.from_expansion() {
                    return;
                }

                span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| {
                    if let Some(snippet) = snippet_opt(cx, inner_span) {
                        db.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
                    }
                })
            },
            None => match replacement {
                RetReplacement::Empty => {
                    span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| {
                        db.span_suggestion(
                            ret_span,
                            "remove `return`",
                            String::new(),
                            Applicability::MachineApplicable,
                        );
                    });
                },
                RetReplacement::Block => {
                    span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| {
                        db.span_suggestion(
                            ret_span,
                            "replace `return` with an empty block",
                            "{}".to_string(),
                            Applicability::MachineApplicable,
                        );
                    });
                },
            },
        }
    }

    // Check for "let x = EXPR; x"
    fn check_let_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        let mut it = block.stmts.iter();

        // we need both a let-binding stmt and an expr
        if_chain! {
            if let Some(retexpr) = it.next_back();
            if let ast::StmtKind::Expr(ref retexpr) = retexpr.node;
            if let Some(stmt) = it.next_back();
            if let ast::StmtKind::Local(ref local) = stmt.node;
            // don't lint in the presence of type inference
            if local.ty.is_none();
            if local.attrs.is_empty();
            if let Some(ref initexpr) = local.init;
            if let ast::PatKind::Ident(_, ident, _) = local.pat.node;
            if let ast::ExprKind::Path(_, ref path) = retexpr.node;
            if match_path_ast(path, &[&*ident.name.as_str()]);
            if !in_external_macro(cx.sess(), initexpr.span);
            if !in_external_macro(cx.sess(), retexpr.span);
            if !in_external_macro(cx.sess(), local.span);
            then {
                span_lint_and_then(
                    cx,
                    LET_AND_RETURN,
                    retexpr.span,
                    "returning the result of a let binding from a block",
                    |err| {
                        err.span_label(local.span, "unnecessary let binding");

                        if let Some(snippet) = snippet_opt(cx, initexpr.span) {
                            err.multipart_suggestion(
                                "return the expression directly",
                                vec![
                                    (local.span, String::new()),
                                    (retexpr.span, snippet),
                                ],
                                Applicability::MachineApplicable,
                            );
                        } else {
                            err.span_help(initexpr.span, "this expression can be directly returned");
                        }
                    },
                );
            }
        }
    }
}

impl EarlyLintPass for Return {
    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, decl: &ast::FnDecl, span: Span, _: ast::NodeId) {
        match kind {
            FnKind::ItemFn(.., block) | FnKind::Method(.., block) => self.check_block_return(cx, block),
            FnKind::Closure(body) => self.check_final_expr(cx, body, Some(body.span), RetReplacement::Empty),
        }
        if_chain! {
            if let ast::FunctionRetTy::Ty(ref ty) = decl.output;
            if let ast::TyKind::Tup(ref vals) = ty.node;
            if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
            then {
                let (rspan, appl) = if let Ok(fn_source) =
                        cx.sess().source_map()
                                 .span_to_snippet(span.with_hi(ty.span.hi())) {
                    if let Some(rpos) = fn_source.rfind("->") {
                        #[allow(clippy::cast_possible_truncation)]
                        (ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
                            Applicability::MachineApplicable)
                    } else {
                        (ty.span, Applicability::MaybeIncorrect)
                    }
                } else {
                    (ty.span, Applicability::MaybeIncorrect)
                };
                span_lint_and_then(cx, UNUSED_UNIT, rspan, "unneeded unit return type", |db| {
                    db.span_suggestion(
                        rspan,
                        "remove the `-> ()`",
                        String::new(),
                        appl,
                    );
                });
            }
        }
    }

    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        self.check_let_return(cx, block);
        if_chain! {
            if let Some(ref stmt) = block.stmts.last();
            if let ast::StmtKind::Expr(ref expr) = stmt.node;
            if is_unit_expr(expr) && !stmt.span.from_expansion();
            then {
                let sp = expr.span;
                span_lint_and_then(cx, UNUSED_UNIT, sp, "unneeded unit expression", |db| {
                    db.span_suggestion(
                        sp,
                        "remove the final `()`",
                        String::new(),
                        Applicability::MachineApplicable,
                    );
                });
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
        match e.node {
            ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
                if is_unit_expr(expr) && !expr.span.from_expansion() {
                    span_lint_and_then(cx, UNUSED_UNIT, expr.span, "unneeded `()`", |db| {
                        db.span_suggestion(
                            expr.span,
                            "remove the `()`",
                            String::new(),
                            Applicability::MachineApplicable,
                        );
                    });
                }
            },
            _ => (),
        }
    }
}

fn attr_is_cfg(attr: &ast::Attribute) -> bool {
    attr.meta_item_list().is_some() && attr.check_name(sym!(cfg))
}

// get the def site
fn get_def(span: Span) -> Option<Span> {
    if span.from_expansion() {
        Some(span.ctxt().outer_expn_data().def_site)
    } else {
        None
    }
}

// is this expr a `()` unit?
fn is_unit_expr(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Tup(ref vals) = expr.node {
        vals.is_empty()
    } else {
        false
    }
}
<|endoftext|>


<commit_before>use futures::{Async, Stream};
use hyper::{self, Method, RequestUri, HttpVersion};
use hyper::header::Headers;
use cookie::Cookie;
use urlencoded::{parse_urlencoded, parse_urlencoded_html_escape};

use std::collections::HashMap;
use std::cell::RefCell;

// mod multipart;

pub struct Request {
    request: hyper::server::Request,
    pub user_data: RefCell<Vec<u8>>,
    form: RefCell<Option<HashMap<String, String>>>,
    sanitize_input: bool,
}

impl Request {
    pub fn new(req: hyper::server::Request, sanitize: bool) -> Self {
        Request {
            request: req,
            user_data: RefCell::new(Vec::new()),
            form: RefCell::new(None),
            sanitize_input: sanitize,
        }
    }

    pub fn method(&self) -> &Method {
        self.request.method()
    }

    pub fn headers(&self) -> &Headers {
        self.request.headers()
    }

    pub fn uri(&self) -> &RequestUri {
        self.request.uri()
    }

    pub fn version(&self) -> &HttpVersion {
        self.request.version()
    }

    pub fn path(&self) -> Option<&str> {
        self.request.path()
    }

    pub fn query(&self) -> Option<&str> {
        self.request.query()
    }

    pub fn form_value<S: Into<String>>(self, key: S) -> Option<String> {
        use std::ops::Deref;
        let key = key.into();

        if *self.form.borrow() == None {
            let mut body = self.request.body();
            match body.poll() {
                Ok(Async::Ready(Some(chunk))) => {
                    let map = if self.sanitize_input {
                        parse_urlencoded_html_escape(chunk.deref())
                    } else {
                        parse_urlencoded(chunk.deref())
                    };
                    let map = match map {
                        Ok(m) => m,
                        Err(e) => {
                            // For now if we can't parse the form we
                            // just return an empty map
                            debug!("Error parsing form: {}", e);
                            HashMap::new()
                        }
                    };
                    *self.form.borrow_mut() = Some(map);
                }
                Ok(Async::Ready(None)) => {
                    *self.form.borrow_mut() = Some(HashMap::new());
                }
                Ok(Async::NotReady) => {
                    *self.form.borrow_mut() = Some(HashMap::new());
                }
                Err(e) => {
                    *self.form.borrow_mut() = Some(HashMap::new());
                }
            }
            /*match *self.body {
                None => return None,
                Some(ref b) => {
                    let body = &b.data[..];
                    info!("Request body: {:?}", body);
                    let m = if self.sanitize_input {
                        parse_urlencoded_html_escape(body)
                    } else {
                        parse_urlencoded(body)
                    };
                    let m = match m {
                        Ok(m) => m,
                        Err(e) => {
                            // For now if we can't parse the form we
                            // just return an empty map
                            debug!("Error parsing form: {}", e);
                            HashMap::new()
                        }
                    };
                    *self.form.borrow_mut() = Some(m);
                }
            }*/
        }

        match *self.form.borrow() {
            Some(ref map) => {
                match map.get(&key) {
                    None => None,
                    Some(s) => Some(s.clone()),
                }
            }
            None => unimplemented!(),
        }
    }
}
/*pub struct Request<'a> {
    pub method: Method,
    pub path: &'a String,
    pub version: &'a enums::Version,
    pub headers: &'a Vec<(enums::Header, String)>,
    pub body: &'a Option<request::Body>,
    pub peer_addr: &'a SocketAddr,
    request: &'a minihttp::Request,
    form: RefCell<Option<HashMap<String, String>>>,
    pub user_data: RefCell<Vec<u8>>,
    sanitize_input: bool,
}

impl<'a> Request<'a> {
    pub fn new(req: &'a minihttp::Request, sanitize: bool) -> Request<'a> {
        Request {
            method: Method::from(&req.method),
            path: &req.path,
            version: &req.version,
            headers: &req.headers,
            body: &req.body,
            peer_addr: &req.peer_addr,
            request: req,
            form: RefCell::new(None),
            user_data: RefCell::new(Vec::new()),
            sanitize_input: sanitize,
        }
    }

    pub fn has_body(&self) -> bool {
        self.request.has_body()
    }

    pub fn host(&self) -> Option<&str> {
        self.request.host()
    }

    pub fn content_type(&self) -> Option<&str> {
        self.request.content_type()
    }

    pub fn content_length(&self) -> Option<u64> {
        self.request.content_length()
    }

    pub fn transfer_encoding(&self) -> Option<&str> {
        self.request.transfer_encoding()
    }

    pub fn form_value<S: Into<String>>(&self, key: S) -> Option<String> {
        let key = key.into();

        if *self.form.borrow() == None {
            match *self.body {
                None => return None,
                Some(ref b) => {
                    let body = &b.data[..];
                    info!("Request body: {:?}", body);
                    let m = if self.sanitize_input {
                        parse_urlencoded_html_escape(body)
                    } else {
                        parse_urlencoded(body)
                    };
                    let m = match m {
                        Ok(m) => m,
                        Err(e) => {
                            // For now if we can't parse the form we
                            // just return an empty map
                            debug!("Error parsing form: {}", e);
                            HashMap::new()
                        }
                    };
                    *self.form.borrow_mut() = Some(m);
                }
            }
        }

        match *self.form.borrow() {
            Some(ref map) => {
                match map.get(&key) {
                    None => None,
                    Some(s) => Some(s.clone()),
                }
            }
            None => unimplemented!(),
        }
    }

    pub fn get_cookies(&self) -> Vec<Cookie> {
        use minihttp::enums::Header;

        let mut cookies = Vec::new();

        for &(ref header, ref value) in self.headers {
            if let &Header::Raw(ref s) = header {
                if s == "Cookie" {
                    let cookie = Cookie::from_bytes(value.as_bytes());
                    cookies.push(cookie);
                }
            }
        }
        cookies
    }
}*/
<commit_msg>Return owned string on req.path()<commit_after>use futures::{Async, Stream};
use hyper::{self, Method, RequestUri, HttpVersion};
use hyper::header::Headers;
use cookie::Cookie;
use urlencoded::{parse_urlencoded, parse_urlencoded_html_escape};

use std::collections::HashMap;
use std::cell::RefCell;

// mod multipart;

pub struct Request {
    request: hyper::server::Request,
    pub user_data: RefCell<Vec<u8>>,
    form: RefCell<Option<HashMap<String, String>>>,
    sanitize_input: bool,
}

impl Request {
    pub fn new(req: hyper::server::Request, sanitize: bool) -> Self {
        Request {
            request: req,
            sanitize_input: sanitize,
            user_data: RefCell::new(Vec::new()),
            form: RefCell::new(None),
        }
    }

    pub fn method(&self) -> &Method {
        self.request.method()
    }

    pub fn headers(&self) -> &Headers {
        self.request.headers()
    }

    pub fn uri(&self) -> &RequestUri {
        self.request.uri()
    }

    pub fn version(&self) -> &HttpVersion {
        self.request.version()
    }

    // TODO(nokaa): We probably don't want to clone/to_string here
    pub fn path(&self) -> Option<String> {
        match *self.request.uri() {
            RequestUri::AbsolutePath { path: ref p, .. } => Some(p.clone()),
            RequestUri::AbsoluteUri(ref url) => Some(url.path().clone().to_string()),
            _ => None,
        }
    }

    pub fn query(&self) -> Option<&str> {
        self.request.query()
    }

    pub fn form_value<S: Into<String>>(self, key: S) -> Option<String> {
        use std::ops::Deref;
        let key = key.into();

        if *self.form.borrow() == None {
            let mut body = self.request.body();
            match body.poll() {
                Ok(Async::Ready(Some(chunk))) => {
                    let map = if self.sanitize_input {
                        parse_urlencoded_html_escape(chunk.deref())
                    } else {
                        parse_urlencoded(chunk.deref())
                    };
                    let map = match map {
                        Ok(m) => m,
                        Err(e) => {
                            // For now if we can't parse the form we
                            // just return an empty map
                            debug!("Error parsing form: {}", e);
                            HashMap::new()
                        }
                    };
                    *self.form.borrow_mut() = Some(map);
                }
                Ok(Async::Ready(None)) => {
                    *self.form.borrow_mut() = Some(HashMap::new());
                }
                Ok(Async::NotReady) => {
                    *self.form.borrow_mut() = Some(HashMap::new());
                }
                Err(e) => {
                    *self.form.borrow_mut() = Some(HashMap::new());
                }
            }
            /*match *self.body {
                None => return None,
                Some(ref b) => {
                    let body = &b.data[..];
                    info!("Request body: {:?}", body);
                    let m = if self.sanitize_input {
                        parse_urlencoded_html_escape(body)
                    } else {
                        parse_urlencoded(body)
                    };
                    let m = match m {
                        Ok(m) => m,
                        Err(e) => {
                            // For now if we can't parse the form we
                            // just return an empty map
                            debug!("Error parsing form: {}", e);
                            HashMap::new()
                        }
                    };
                    *self.form.borrow_mut() = Some(m);
                }
            }*/
        }

        match *self.form.borrow() {
            Some(ref map) => {
                match map.get(&key) {
                    None => None,
                    Some(s) => Some(s.clone()),
                }
            }
            None => unimplemented!(),
        }
    }
}
/*pub struct Request<'a> {
    pub method: Method,
    pub path: &'a String,
    pub version: &'a enums::Version,
    pub headers: &'a Vec<(enums::Header, String)>,
    pub body: &'a Option<request::Body>,
    pub peer_addr: &'a SocketAddr,
    request: &'a minihttp::Request,
    form: RefCell<Option<HashMap<String, String>>>,
    pub user_data: RefCell<Vec<u8>>,
    sanitize_input: bool,
}

impl<'a> Request<'a> {
    pub fn new(req: &'a minihttp::Request, sanitize: bool) -> Request<'a> {
        Request {
            method: Method::from(&req.method),
            path: &req.path,
            version: &req.version,
            headers: &req.headers,
            body: &req.body,
            peer_addr: &req.peer_addr,
            request: req,
            form: RefCell::new(None),
            user_data: RefCell::new(Vec::new()),
            sanitize_input: sanitize,
        }
    }

    pub fn has_body(&self) -> bool {
        self.request.has_body()
    }

    pub fn host(&self) -> Option<&str> {
        self.request.host()
    }

    pub fn content_type(&self) -> Option<&str> {
        self.request.content_type()
    }

    pub fn content_length(&self) -> Option<u64> {
        self.request.content_length()
    }

    pub fn transfer_encoding(&self) -> Option<&str> {
        self.request.transfer_encoding()
    }

    pub fn form_value<S: Into<String>>(&self, key: S) -> Option<String> {
        let key = key.into();

        if *self.form.borrow() == None {
            match *self.body {
                None => return None,
                Some(ref b) => {
                    let body = &b.data[..];
                    info!("Request body: {:?}", body);
                    let m = if self.sanitize_input {
                        parse_urlencoded_html_escape(body)
                    } else {
                        parse_urlencoded(body)
                    };
                    let m = match m {
                        Ok(m) => m,
                        Err(e) => {
                            // For now if we can't parse the form we
                            // just return an empty map
                            debug!("Error parsing form: {}", e);
                            HashMap::new()
                        }
                    };
                    *self.form.borrow_mut() = Some(m);
                }
            }
        }

        match *self.form.borrow() {
            Some(ref map) => {
                match map.get(&key) {
                    None => None,
                    Some(s) => Some(s.clone()),
                }
            }
            None => unimplemented!(),
        }
    }

    pub fn get_cookies(&self) -> Vec<Cookie> {
        use minihttp::enums::Header;

        let mut cookies = Vec::new();

        for &(ref header, ref value) in self.headers {
            if let &Header::Raw(ref s) = header {
                if s == "Cookie" {
                    let cookie = Cookie::from_bytes(value.as_bytes());
                    cookies.push(cookie);
                }
            }
        }
        cookies
    }
}*/
<|endoftext|>