<commit_before>// Copyright 2017 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::path::PathBuf;

use argh::FromArgs;
use cros_async::ExecutorKind;
use devices::virtio::block::block::DiskOption;
use devices::virtio::vhost::user::device;
use devices::virtio::vhost::user::VhostUserParams;
use devices::SerialParameters;

use crate::crosvm::config::from_key_values;
use crate::crosvm::config::validate_serial_parameters;
use crate::crosvm::config::JailConfig;

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Devices
pub enum DeviceSubcommand {
    Console(device::ConsoleOptions),
    #[cfg(feature = "audio")]
    Snd(device::SndOptions),
    Fs(device::FsOptions),
    Vsock(device::VsockOptions),
    Wl(device::WlOptions),
}

fn parse_vu_serial_options(s: &str) -> Result<VhostUserParams<SerialParameters>, String> {
    let params: VhostUserParams<SerialParameters> = from_key_values(s)?;

    validate_serial_parameters(&params.device)?;

    Ok(params)
}

#[argh_helpers::pad_description_for_argh]
#[derive(FromArgs)]
#[argh(subcommand, name = "devices")]
/// Start one or several jailed device processes.
pub struct DevicesCommand {
    /// configure async executor backend to "uring" or "epoll" (default).
    #[argh(option, arg_name = "EXECUTOR")]
    pub async_executor: Option<ExecutorKind>,

    #[argh(switch)]
    /// disable sandboxing. Will nullify the --jail option if it was present.
    pub disable_sandbox: bool,

    #[argh(
        option,
        arg_name = "jail configuration",
        default = "Default::default()"
    )]
    /// set up the jail configuration.
    /// Possible key values:
    ///     pivot-root=/path - Path to empty directory to use for
    ///         sandbox pivot root.
    ///     seccomp-policy-dir=/path - Path to seccomp .policy files
    ///     seccomp-log-failures=(true|false) - Log seccomp filter
    ///         failures instead of them being fatal.
    pub jail: JailConfig,

    #[argh(
        option,
        arg_name = "vhost=PATH,type=TYPE,[hardware=HW,num=NUM,path=PATH,input=PATH,console,earlycon,stdin]",
        from_str_fn(parse_vu_serial_options)
    )]
    /// comma separated key=value pairs for setting up serial
    /// devices. Can be given more than once.
    /// Possible key values:
    ///     vhost=PATH - Path to a vhost-user endpoint to listen to.
    ///        This parameter must be given in first position.
    ///     type=(stdout,syslog,sink,file) - Where to route the
    ///        serial device
    ///     hardware=(serial,virtio-console) - Which type of serial
    ///        hardware to emulate. Defaults to 8250 UART (serial).
    ///     num=(1,2,3,4) - Serial Device Number. If not provided,
    ///        num will default to 1.
    ///     path=PATH - The path to the file to write to when
    ///        type=file
    ///     input=PATH - The path to the file to read from when not
    ///        stdin
    ///     console - Use this serial device as the guest console.
    ///        Can only be given once. Will default to first
    ///        serial port if not provided.
    ///     earlycon - Use this serial device as the early console.
    ///        Can only be given once.
    ///     stdin - Direct standard input to this serial device.
    ///        Can only be given once. Will default to first serial
    ///        port if not provided.
    pub serial: Vec<VhostUserParams<SerialParameters>>,

    #[argh(option, arg_name = "block options")]
    /// start a block device (see help from run command for options)
    pub block: Vec<VhostUserParams<DiskOption>>,

    #[argh(option, short = 's', arg_name = "PATH")]
    /// path to put the control socket.
    pub control_socket: Option<PathBuf>,
}

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Commands
pub enum Commands {
    #[cfg(unix)]
    Devices(DevicesCommand),
}
<commit_msg>crosvm: cmdline: Improve "devices"'s help for block device<commit_after>// Copyright 2017 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::path::PathBuf;

use argh::FromArgs;
use cros_async::ExecutorKind;
use devices::virtio::block::block::DiskOption;
use devices::virtio::vhost::user::device;
use devices::virtio::vhost::user::VhostUserParams;
use devices::SerialParameters;

use crate::crosvm::config::from_key_values;
use crate::crosvm::config::validate_serial_parameters;
use crate::crosvm::config::JailConfig;

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Devices
pub enum DeviceSubcommand {
    Console(device::ConsoleOptions),
    #[cfg(feature = "audio")]
    Snd(device::SndOptions),
    Fs(device::FsOptions),
    Vsock(device::VsockOptions),
    Wl(device::WlOptions),
}

fn parse_vu_serial_options(s: &str) -> Result<VhostUserParams<SerialParameters>, String> {
    let params: VhostUserParams<SerialParameters> = from_key_values(s)?;

    validate_serial_parameters(&params.device)?;

    Ok(params)
}

#[argh_helpers::pad_description_for_argh]
#[derive(FromArgs)]
#[argh(subcommand, name = "devices")]
/// Start one or several jailed device processes.
pub struct DevicesCommand {
    /// configure async executor backend to "uring" or "epoll" (default).
    #[argh(option, arg_name = "EXECUTOR")]
    pub async_executor: Option<ExecutorKind>,

    #[argh(switch)]
    /// disable sandboxing. Will nullify the --jail option if it was present.
    pub disable_sandbox: bool,

    #[argh(
        option,
        arg_name = "jail configuration",
        default = "Default::default()"
    )]
    /// set up the jail configuration.
    /// Possible key values:
    ///     pivot-root=/path - Path to empty directory to use for
    ///         sandbox pivot root.
    ///     seccomp-policy-dir=/path - Path to seccomp .policy files
    ///     seccomp-log-failures=(true|false) - Log seccomp filter
    ///         failures instead of them being fatal.
    pub jail: JailConfig,

    #[argh(
        option,
        arg_name = "vhost=PATH,type=TYPE,[hardware=HW,num=NUM,path=PATH,input=PATH,console,earlycon,stdin]",
        from_str_fn(parse_vu_serial_options)
    )]
    /// comma separated key=value pairs for setting up serial
    /// devices. Can be given more than once.
    /// Possible key values:
    ///     vhost=PATH - Path to a vhost-user endpoint to listen to.
    ///        This parameter must be given in first position.
    ///     type=(stdout,syslog,sink,file) - Where to route the
    ///        serial device
    ///     hardware=(serial,virtio-console) - Which type of serial
    ///        hardware to emulate. Defaults to 8250 UART (serial).
    ///     num=(1,2,3,4) - Serial Device Number. If not provided,
    ///        num will default to 1.
    ///     path=PATH - The path to the file to write to when
    ///        type=file
    ///     input=PATH - The path to the file to read from when not
    ///        stdin
    ///     console - Use this serial device as the guest console.
    ///        Can only be given once. Will default to first
    ///        serial port if not provided.
    ///     earlycon - Use this serial device as the early console.
    ///        Can only be given once.
    ///     stdin - Direct standard input to this serial device.
    ///        Can only be given once. Will default to first serial
    ///        port if not provided.
    pub serial: Vec<VhostUserParams<SerialParameters>>,

    #[argh(option, arg_name = "block options")]
    /// start a block device.
    /// The value must be a comma separated key-value pairs in the
    /// form of `vhost=PATH[,block options]`.
    /// Possible key values:
    ///     vhost=PATH - Path to a vhost-user endpoint to listen to.
    ///        This parameter must be given in first position.
    ///     block options:
    ///        See help from `crosvm run` command.
    pub block: Vec<VhostUserParams<DiskOption>>,

    #[argh(option, short = 's', arg_name = "PATH")]
    /// path to put the control socket.
    pub control_socket: Option<PathBuf>,
}

#[derive(FromArgs)]
#[argh(subcommand)]
/// Unix Commands
pub enum Commands {
    #[cfg(unix)]
    Devices(DevicesCommand),
}
<|endoftext|>


<commit_before>use crate::backtrace::{Backtrace, BacktraceFrame, BacktraceSymbol};
use serde::ser::{Serialize, SerializeSeq, Serializer};
use serde_json::{self, Value};
use std::collections::HashMap;

#[derive(Debug)]
pub struct NoticeTrace {
    frames: Vec<NoticeFrame>,
}

impl NoticeTrace {
    fn new(frames: Vec<NoticeFrame>) -> NoticeTrace {
        NoticeTrace { frames }
    }

    pub fn frames(&self) -> Vec<NoticeFrame> {
        self.frames.clone()
    }
}

impl From<&Backtrace> for NoticeTrace {
    fn from(backtrace: &Backtrace) -> NoticeTrace {
        let mut frames: Vec<NoticeFrame> = vec![];
        for f in backtrace.frames() {
            frames.append(&mut NoticeFrame::unroll_frame_symbols(&f));
        }
        NoticeTrace { frames }
    }
}

impl Serialize for NoticeTrace {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut seq = serializer.serialize_seq(Some(self.frames.len()))?;
        for element in self.frames() {
            seq.serialize_element(&element)?;
        }
        seq.end()
    }
}

impl From<NoticeTrace> for Value {
    fn from(notice_backtrace: NoticeTrace) -> Value {
        serde_json::json!(notice_backtrace)
    }
}

#[derive(Debug, Serialize, Clone)]
pub struct NoticeFrame {
    pub file: String,
    pub function: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub line: Option<u32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<HashMap<i32, String>>,
}

impl NoticeFrame {
    fn unroll_frame_symbols(frame: &BacktraceFrame) -> Vec<NoticeFrame> {
        frame.symbols().iter().map(NoticeFrame::from).collect()
    }
}

impl From<&BacktraceSymbol> for NoticeFrame {
    fn from(symbol: &BacktraceSymbol) -> NoticeFrame {
        let filename = match symbol.filename() {
            Some(f) => f
                .to_str()
                .expect("Backtrace frame's filename was not valid unicode")
                .to_string(),
            None => "(anonymous)".to_string(),
        };
        let function_name = symbol
            .name()
            .expect("Backtrace frame doesn't have a function name")
            .to_string();

        NoticeFrame {
            file: filename,
            line: symbol.lineno(),
            function: function_name,
            code: None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{NoticeFrame, NoticeTrace};
    use crate::backtrace::Backtrace;
    use std::convert::From;

    #[test]
    fn backtrace_contains_current_function_frame() {
        let function_name: String = "backtrace_contains_current_function_frame".to_string();
        // This test builds a new backtrace object and asserts that
        // the current function exists somewhere in the resulting
        // list of frames.
        let backtrace = Backtrace::new();
        let selected_frames: Vec<NoticeFrame> = NoticeTrace::from(&backtrace)
            .frames()
            .into_iter()
            .filter(|f| f.function.contains(&function_name))
            .collect();

        assert_gt!(selected_frames.len(), 0);
    }

    #[test]
    fn backtrace_unrolls_multiple_symboles() {
        let function_name: String = "backtrace_unrolls_multiple_symboles".to_string();
        let nested_frame_line: u32 = 128;
        // This backtrace is generated from within a nested enclosure so
        // that the backtraces creates a single frame with two symboles
        let fn_backtrace = || (|| Backtrace::new())();
        let backtrace = fn_backtrace();
        let selected_frames: Vec<NoticeFrame> = NoticeTrace::from(&backtrace)
            .frames()
            .into_iter()
            .filter(|f| f.function.contains(&function_name) && f.line == Some(nested_frame_line))
            .collect();

        assert_gt!(selected_frames.len(), 1);
    }

    #[test]
    fn json_backtrace_is_array_of_objects() {
        use serde_json::{self, Value};

        let backtrace = Backtrace::new();
        let notice_backtrace = NoticeTrace::from(&backtrace);
        let json_backtrace = Value::from(notice_backtrace);

        assert_matches!(json_backtrace, Value::Array(_));
        assert_matches!(json_backtrace[0], Value::Object(_));
    }
}
<commit_msg>Fix line number in flakey test<commit_after>use crate::backtrace::{Backtrace, BacktraceFrame, BacktraceSymbol};
use serde::ser::{Serialize, SerializeSeq, Serializer};
use serde_json::{self, Value};
use std::collections::HashMap;

#[derive(Debug)]
pub struct NoticeTrace {
    frames: Vec<NoticeFrame>,
}

impl NoticeTrace {
    fn new(frames: Vec<NoticeFrame>) -> NoticeTrace {
        NoticeTrace { frames }
    }

    pub fn frames(&self) -> Vec<NoticeFrame> {
        self.frames.clone()
    }
}

impl From<&Backtrace> for NoticeTrace {
    fn from(backtrace: &Backtrace) -> NoticeTrace {
        let mut frames: Vec<NoticeFrame> = vec![];
        for f in backtrace.frames() {
            frames.append(&mut NoticeFrame::unroll_frame_symbols(&f));
        }
        NoticeTrace { frames }
    }
}

impl Serialize for NoticeTrace {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut seq = serializer.serialize_seq(Some(self.frames.len()))?;
        for element in self.frames() {
            seq.serialize_element(&element)?;
        }
        seq.end()
    }
}

impl From<NoticeTrace> for Value {
    fn from(notice_backtrace: NoticeTrace) -> Value {
        serde_json::json!(notice_backtrace)
    }
}

#[derive(Debug, Serialize, Clone)]
pub struct NoticeFrame {
    pub file: String,
    pub function: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub line: Option<u32>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<HashMap<i32, String>>,
}

impl NoticeFrame {
    fn unroll_frame_symbols(frame: &BacktraceFrame) -> Vec<NoticeFrame> {
        frame.symbols().iter().map(NoticeFrame::from).collect()
    }
}

impl From<&BacktraceSymbol> for NoticeFrame {
    fn from(symbol: &BacktraceSymbol) -> NoticeFrame {
        let filename = match symbol.filename() {
            Some(f) => f
                .to_str()
                .expect("Backtrace frame's filename was not valid unicode")
                .to_string(),
            None => "(anonymous)".to_string(),
        };
        let function_name = symbol
            .name()
            .expect("Backtrace frame doesn't have a function name")
            .to_string();

        NoticeFrame {
            file: filename,
            line: symbol.lineno(),
            function: function_name,
            code: None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{NoticeFrame, NoticeTrace};
    use crate::backtrace::Backtrace;
    use std::convert::From;

    #[test]
    fn backtrace_contains_current_function_frame() {
        let function_name: String = "backtrace_contains_current_function_frame".to_string();
        // This test builds a new backtrace object and asserts that
        // the current function exists somewhere in the resulting
        // list of frames.
        let backtrace = Backtrace::new();
        let selected_frames: Vec<NoticeFrame> = NoticeTrace::from(&backtrace)
            .frames()
            .into_iter()
            .filter(|f| f.function.contains(&function_name))
            .collect();

        assert_gt!(selected_frames.len(), 0);
    }

    #[test]
    fn backtrace_unrolls_multiple_symboles() {
        let function_name: String = "backtrace_unrolls_multiple_symboles".to_string();
        let nested_frame_line: u32 = 119;
        // This backtrace is generated from within a nested enclosure so
        // that the backtraces creates a single frame with two symboles
        let fn_backtrace = || (|| Backtrace::new())();
        let backtrace = fn_backtrace();
        let selected_frames: Vec<NoticeFrame> = NoticeTrace::from(&backtrace)
            .frames()
            .into_iter()
            .filter(|f| f.function.contains(&function_name) && f.line == Some(nested_frame_line))
            .collect();

        assert_gt!(selected_frames.len(), 1);
    }

    #[test]
    fn json_backtrace_is_array_of_objects() {
        use serde_json::{self, Value};

        let backtrace = Backtrace::new();
        let notice_backtrace = NoticeTrace::from(&backtrace);
        let json_backtrace = Value::from(notice_backtrace);

        assert_matches!(json_backtrace, Value::Array(_));
        assert_matches!(json_backtrace[0], Value::Object(_));
    }
}
<|endoftext|>


<commit_before>mod x86;
//mod arm;

pub struct Intrinsic {
  pub inputs: Vec<Type>,
  pub output: Type,

  pub definition: IntrinsicDef,
}

#[derive(Clone, Hash, Eq, PartialEq)]
pub enum Type {
    Void,
    Integer(/* signed */ bool, u8, /* llvm width */ u8),
    Float(u8),
    Pointer(Box<Type>, Option<Box<Type>>, /* const */ bool),
    Vector(Box<Type>, Option<Box<Type>>, u8),
    Aggregate(bool, Vec<Type>),
}

pub enum IntrinsicDef {
    Named(&'static str),
}

fn i(width: u8) -> Type { Type::Integer(true, width, width) }
fn i_(width: u8, llvm_width: u8) -> Type { Type::Integer(true, width, llvm_width) }
fn u(width: u8) -> Type { Type::Integer(false, width, width) }
#[allow(dead_code)]
fn u_(width: u8, llvm_width: u8) -> Type { Type::Integer(false, width, llvm_width) }
fn f(width: u8) -> Type { Type::Float(width) }
fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), None, length) }
fn v_(x: Type, bitcast: Type, length: u8) -> Type {
    Type::Vector(Box::new(x), Some(Box::new(bitcast)), length)
}
fn agg(flatten: bool, types: Vec<Type>) -> Type {
    Type::Aggregate(flatten, types)
}
fn p(const_: bool, elem: Type, llvm_elem: Option<Type>) -> Type {
    Type::Pointer(Box::new(elem), llvm_elem.map(Box::new), const_)
}
fn void() -> Type {
    Type::Void
}

impl Intrinsic {
  pub fn find<'tcx>(name: &str) -> Option<Intrinsic> {
    x86::find(name)
    // if name.starts_with("x86_") {
    //   x86::find(tcx, name)
    // } else if name.starts_with("arm_") {
    //   arm::find(tcx, name)
    // } else if name.starts_with("aarch64_") {
    //   aarch64::find(tcx, name)
    // } else {
    //   None
    // }
  }
}<commit_msg>Fix wrong indent.<commit_after>mod x86;
//mod arm;
//mod aarch64;

pub struct Intrinsic {
  pub inputs: Vec<Type>,
  pub output: Type,

  pub definition: IntrinsicDef,
}

#[derive(Clone, Hash, Eq, PartialEq)]
pub enum Type {
  Void,
  Integer(/* signed */ bool, u8, /* llvm width */ u8),
  Float(u8),
  Pointer(Box<Type>, Option<Box<Type>>, /* const */ bool),
  Vector(Box<Type>, Option<Box<Type>>, u8),
  Aggregate(bool, Vec<Type>),
}

pub enum IntrinsicDef {
  Named(&'static str),
}

fn i(width: u8) -> Type { Type::Integer(true, width, width) }
fn i_(width: u8, llvm_width: u8) -> Type { Type::Integer(true, width, llvm_width) }
fn u(width: u8) -> Type { Type::Integer(false, width, width) }
#[allow(dead_code)]
fn u_(width: u8, llvm_width: u8) -> Type { Type::Integer(false, width, llvm_width) }
fn f(width: u8) -> Type { Type::Float(width) }
fn v(x: Type, length: u8) -> Type { Type::Vector(Box::new(x), None, length) }
fn v_(x: Type, bitcast: Type, length: u8) -> Type {
    Type::Vector(Box::new(x), Some(Box::new(bitcast)), length)
}
fn agg(flatten: bool, types: Vec<Type>) -> Type {
    Type::Aggregate(flatten, types)
}
fn p(const_: bool, elem: Type, llvm_elem: Option<Type>) -> Type {
    Type::Pointer(Box::new(elem), llvm_elem.map(Box::new), const_)
}
fn void() -> Type {
    Type::Void
}

impl Intrinsic {
  pub fn find<'tcx>(name: &str) -> Option<Intrinsic> {
    x86::find(name)
    // if name.starts_with("x86_") {
    //   x86::find(tcx, name)
    // } else if name.starts_with("arm_") {
    //   arm::find(tcx, name)
    // } else if name.starts_with("aarch64_") {
    //   aarch64::find(tcx, name)
    // } else {
    //   None
    // }
  }
}<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::iter::Iterator;
use std::fmt;

use serde::{json, Deserialize};
use hyper::method::Method;

use response::{self, RawPagedResponse, NamedResponse, NotArray};
use request::{BaseRequest, DoRequest};
use request::PagedRequest;

pub struct RequestBuilder<'t, T> {
    pub auth: &'t str,
    pub method: Method,
    pub url: String,
    pub resp_t: PhantomData<*const T>,
    pub body: Option<String>
}

impl<'t, T> RequestBuilder<'t, T> {
    pub fn with_auth(auth: &'t str) -> RequestBuilder<'t, T> {
        RequestBuilder {
            auth: auth,
            method: Method::Get,
            url: String::new(),
            resp_t: PhantomData,
            body: None
        }
    }
    pub fn new<S>(auth: &'t str, url: S)
                  -> RequestBuilder<'t, T>
                  where S: Into<String> {
        RequestBuilder {
            auth: auth,
            method: Method::Get,
            url: url.into(),
            resp_t: PhantomData,
            body: None
        }
    }
}

impl<'t, T> fmt::Display for RequestBuilder<'t, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "method: {}\n\
                content-type: application/json\n\
                authorization: Bearer {}\n\
                url: {}\n\
                body: {}\n",
            self.method,
            self.auth,
            if !self.url.is_empty() { self.url.clone() } else { "None".to_owned() },
            if let Some(ref bdy) = self.body { format!("\n\t{}", bdy) } else { "None".to_owned() } )
    }
}

impl<'t, T> BaseRequest for RequestBuilder<'t, T> {
    fn auth(&self) -> &str {
        self.auth
    }
    fn url(&self) -> &str {
        &self.url[..]
    }
    fn method(&self) -> Method {
        self.method.clone()
    }
    fn body(&self) -> Option<String> {
        self.body.clone()
    }
}

// Can't use because of impl for DoRequest<Vec<T>>, waiting on negative trait bounds
// impl<'t, T: !Iterator> DoRequest<T> for RequestBuilder<'t, T> { }

impl<'t, I> PagedRequest for RequestBuilder<'t, Vec<I>>
                                              where I: Deserialize + NamedResponse + NotArray {
    type Item = I;
    fn retrieve_single_page(&self, url: String) -> Result<RawPagedResponse<I>, String> {
        debug!("Inside retrieve_single_page() with url: {}", &url[..]);
        if url.is_empty() {
            debug!("No url provided");
            return Err("No URL provided".to_owned())
        }
        let mut rb: RequestBuilder<'t, Vec<I>> = RequestBuilder::with_auth(self.auth);
        rb.url = url.clone();
        match rb.retrieve_json() {
            Ok(ref s) => {
                 // FIXME \/ \/
                let mut name = <I as NamedResponse>::name().into_owned();
                name.push('s');
                let re = regex!(&format!("\"{}\"", name));
                let json_str = &re.replace(&s[..], "\"collection\"");
                match json::from_str::<response::RawPagedResponse<I>>(json_str) {
                // FIXME ^^
                    Ok(val) => {
                        return Ok(val)
                    },
                    Err(e) => {
                        debug!("Error getting objects: {}", e.to_string());
                        return Err(e.to_string())
                    }
                }
            },
            Err(e) => {
                debug!("Error getting json: {}", e.to_string());
                return Err(e.to_string())
            }
        }
    }
}

impl<'t, I> DoRequest<Vec<I>> for RequestBuilder<'t, Vec<I>>
                                where I: Deserialize + NamedResponse + NotArray {
    fn retrieve(&self) -> Result<Vec<I>, String> {
        debug!("Inside retrieve() for  paged request");
        debug!("Getting json...");
        match self.retrieve_json() {
            Ok(ref s) => {
                debug!("Sucessfully retrieved json");
                 // FIXME \/ \/
                let mut name = <I as NamedResponse>::name().into_owned();
                name.push('s');
                debug!("Replacing {} with collection", &name[..]);
                let re = regex!(&format!("\"{}\"", name));
                let res = &re.replace(&s[..], "\"collection\"");
                debug!("Getting object from json string");
                match json::from_str::<response::RawPagedResponse<I>>(res) {
                // FIXME ^^
                    Ok(mut val) => {
                        debug!("Sucessfully retrieved object");
                        let mut regs = vec![];
                        regs.append(&mut val.collection);
                        let mut url = if val.links.pages.is_some() && val.links.pages.clone().unwrap().next.is_some() {
                            val.links.pages.clone().unwrap().next.clone().unwrap()
                        } else {
                            String::new()
                        };
                        debug!("Next page URL: {}", &url[..]);
                        while let Ok(mut page) = self.retrieve_single_page(url.clone()) {
                            regs.append(&mut page.collection);
                            url = if page.links.pages.is_some() && page.links.pages.clone().unwrap().next.is_some() {
                                page.links.pages.clone().unwrap().next.clone().unwrap()
                            } else {
                                String::new()
                            };
                            debug!("Next page URL: {}", &url[..]);
                        }
                        Ok(regs)
                    },
                    Err(e) => {
                        debug!("Error getting object: {}", e.to_string());
                        Err(e.to_string())
                    }
                }
            },
            Err(e) => {
                debug!("Error getting json: {}", e.to_string());
                Err(e.to_string())
            }
        }
    }
}

impl<'t> DoRequest<response::HeaderOnly> for RequestBuilder<'t, response::HeaderOnly> {
    fn retrieve(&self) -> Result<response::HeaderOnly, String> {
        self.retrieve_header()
    }
}<commit_msg>imp: fixes ssh_keys api<commit_after>use std::marker::PhantomData;
use std::iter::Iterator;
use std::fmt;

use serde::{json, Deserialize};
use hyper::method::Method;

use response::{self, RawPagedResponse, NamedResponse, NotArray};
use request::{BaseRequest, DoRequest};
use request::PagedRequest;

pub struct RequestBuilder<'t, T> {
    pub auth: &'t str,
    pub method: Method,
    pub url: String,
    pub resp_t: PhantomData<*const T>,
    pub body: Option<String>
}

impl<'t, T> RequestBuilder<'t, T> {
    pub fn with_auth(auth: &'t str) -> RequestBuilder<'t, T> {
        RequestBuilder {
            auth: auth,
            method: Method::Get,
            url: String::new(),
            resp_t: PhantomData,
            body: None
        }
    }
    pub fn new<S>(auth: &'t str, url: S)
                  -> RequestBuilder<'t, T>
                  where S: Into<String> {
        RequestBuilder {
            auth: auth,
            method: Method::Get,
            url: url.into(),
            resp_t: PhantomData,
            body: None
        }
    }
}

impl<'t, T> fmt::Display for RequestBuilder<'t, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "method: {}\n\
                content-type: application/json\n\
                authorization: Bearer {}\n\
                url: {}\n\
                body: {}\n",
            self.method,
            self.auth,
            if !self.url.is_empty() { self.url.clone() } else { "None".to_owned() },
            if let Some(ref bdy) = self.body { format!("{}", bdy) } else { "None".to_owned() } )
    }
}

impl<'t, T> BaseRequest for RequestBuilder<'t, T> {
    fn auth(&self) -> &str {
        self.auth
    }
    fn url(&self) -> &str {
        &self.url[..]
    }
    fn method(&self) -> Method {
        self.method.clone()
    }
    fn body(&self) -> Option<String> {
        self.body.clone()
    }
}

// Can't use because of impl for DoRequest<Vec<T>>, waiting on negative trait bounds
// impl<'t, T: !Iterator> DoRequest<T> for RequestBuilder<'t, T> { }

impl<'t, I> PagedRequest for RequestBuilder<'t, Vec<I>>
                                              where I: Deserialize + NamedResponse + NotArray {
    type Item = I;
    fn retrieve_single_page(&self, url: String) -> Result<RawPagedResponse<I>, String> {
        debug!("Inside retrieve_single_page() with url: {}", &url[..]);
        if url.is_empty() {
            debug!("No url provided");
            return Err("No URL provided".to_owned())
        }
        let mut rb: RequestBuilder<'t, Vec<I>> = RequestBuilder::with_auth(self.auth);
        rb.url = url.clone();
        match rb.retrieve_json() {
            Ok(ref s) => {
                 // FIXME \/ \/
                let mut name = <I as NamedResponse>::name().into_owned();
                name.push('s');
                let re = regex!(&format!("\"{}\"", name));
                let json_str = &re.replace(&s[..], "\"collection\"");
                match json::from_str::<response::RawPagedResponse<I>>(json_str) {
                // FIXME ^^
                    Ok(val) => {
                        return Ok(val)
                    },
                    Err(e) => {
                        debug!("Error getting objects: {}", e.to_string());
                        return Err(e.to_string())
                    }
                }
            },
            Err(e) => {
                debug!("Error getting json: {}", e.to_string());
                return Err(e.to_string())
            }
        }
    }
}

impl<'t, I> DoRequest<Vec<I>> for RequestBuilder<'t, Vec<I>>
                                where I: Deserialize + NamedResponse + NotArray {
    fn retrieve(&self) -> Result<Vec<I>, String> {
        debug!("Inside retrieve() for  paged request");
        debug!("Getting json...");
        match self.retrieve_json() {
            Ok(ref s) => {
                debug!("Sucessfully retrieved json");
                 // FIXME \/ \/
                let mut name = <I as NamedResponse>::name().into_owned();
                name.push('s');
                debug!("Replacing {} with collection", &name[..]);
                let re = regex!(&format!("\"{}\"", name));
                let res = &re.replace(&s[..], "\"collection\"");
                debug!("Getting object from json string");
                match json::from_str::<response::RawPagedResponse<I>>(res) {
                // FIXME ^^
                    Ok(mut val) => {
                        debug!("Sucessfully retrieved object");
                        let mut regs = vec![];
                        regs.append(&mut val.collection);
                        let mut url = if val.links.pages.is_some() && val.links.pages.clone().unwrap().next.is_some() {
                            val.links.pages.clone().unwrap().next.clone().unwrap()
                        } else {
                            String::new()
                        };
                        debug!("Next page URL: {}", &url[..]);
                        while let Ok(mut page) = self.retrieve_single_page(url.clone()) {
                            regs.append(&mut page.collection);
                            url = if page.links.pages.is_some() && page.links.pages.clone().unwrap().next.is_some() {
                                page.links.pages.clone().unwrap().next.clone().unwrap()
                            } else {
                                String::new()
                            };
                            debug!("Next page URL: {}", &url[..]);
                        }
                        Ok(regs)
                    },
                    Err(e) => {
                        debug!("Error getting object: {}", e.to_string());
                        Err(e.to_string())
                    }
                }
            },
            Err(e) => {
                debug!("Error getting json: {}", e.to_string());
                Err(e.to_string())
            }
        }
    }
}

impl<'t> DoRequest<response::HeaderOnly> for RequestBuilder<'t, response::HeaderOnly> {
    fn retrieve(&self) -> Result<response::HeaderOnly, String> {
        self.retrieve_header()
    }
}<|endoftext|>


<commit_before>// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]
#![feature(c_variadic)]
#![feature(unwind_attributes)]
#![no_std]
use core::ffi::VaList;

extern "C" {
    fn foreign_c_variadic_0(_: i32, ...);
    fn foreign_c_variadic_1(_: VaList, ...);
}

#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_0() {
    // Ensure that we correctly call foreign C-variadic functions.
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0)
    foreign_c_variadic_0(0);
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42)
    foreign_c_variadic_0(0, 42i32);
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024)
    foreign_c_variadic_0(0, 42i32, 1024i32);
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024, i32 0)
    foreign_c_variadic_0(0, 42i32, 1024i32, 0i32);
}

// Ensure that we do not remove the `va_list` passed to the foreign function when
// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics.
#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap)
    foreign_c_variadic_1(ap);
}

#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 42)
    foreign_c_variadic_1(ap, 42i32);
}
#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42)
    foreign_c_variadic_1(ap, 2i32, 42i32);
}

#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42, i32 0)
    foreign_c_variadic_1(ap, 2i32, 42i32, 0i32);
}

// Ensure that `va_start` and `va_end` are properly injected.
#[no_mangle]
pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 {
    // CHECK: call void @llvm.va_start
    let mut sum = 0;
    for _ in 0..n {
        sum += ap.arg::<i32>();
    }
    sum
    // CHECK: call void @llvm.va_end
}

// Ensure that we generate the correct `call` signature when calling a Rust
// defined C-variadic.
pub unsafe fn test_c_variadic_call() {
    // CHECK: call i32 (i32, ...) @c_variadic(i32 0)
    c_variadic(0);
    // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42)
    c_variadic(0, 42i32);
    // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024)
    c_variadic(0, 42i32, 1024i32);
    // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024, i32 0)
    c_variadic(0, 42i32, 1024i32, 0i32);
}
<commit_msg>Rollup merge of #64256 - smaeul:patch/powerpc64-tests, r=alexcrichton<commit_after>// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength

#![crate_type = "lib"]
#![feature(c_variadic)]
#![feature(unwind_attributes)]
#![no_std]
use core::ffi::VaList;

extern "C" {
    fn foreign_c_variadic_0(_: i32, ...);
    fn foreign_c_variadic_1(_: VaList, ...);
}

#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_0() {
    // Ensure that we correctly call foreign C-variadic functions.
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0)
    foreign_c_variadic_0(0);
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42)
    foreign_c_variadic_0(0, 42i32);
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
    foreign_c_variadic_0(0, 42i32, 1024i32);
    // CHECK: invoke void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
    foreign_c_variadic_0(0, 42i32, 1024i32, 0i32);
}

// Ensure that we do not remove the `va_list` passed to the foreign function when
// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics.
#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap)
    foreign_c_variadic_1(ap);
}

#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42)
    foreign_c_variadic_1(ap, 42i32);
}
#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42)
    foreign_c_variadic_1(ap, 2i32, 42i32);
}

#[unwind(aborts)] // FIXME(#58794)
pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) {
    // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0)
    foreign_c_variadic_1(ap, 2i32, 42i32, 0i32);
}

// Ensure that `va_start` and `va_end` are properly injected.
#[no_mangle]
pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 {
    // CHECK: call void @llvm.va_start
    let mut sum = 0;
    for _ in 0..n {
        sum += ap.arg::<i32>();
    }
    sum
    // CHECK: call void @llvm.va_end
}

// Ensure that we generate the correct `call` signature when calling a Rust
// defined C-variadic.
pub unsafe fn test_c_variadic_call() {
    // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0)
    c_variadic(0);
    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42)
    c_variadic(0, 42i32);
    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
    c_variadic(0, 42i32, 1024i32);
    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
    c_variadic(0, 42i32, 1024i32, 0i32);
}
<|endoftext|>


<commit_before>extern crate gtk;
use gtk::prelude::*;

extern crate lazy_static;

use metadata::{Chapter, Timestamp};

const START_COL: i32 = 0;
const END_COL: i32 = 1;
const TITLE_COL: i32 = 2;
const START_STR_COL: i32 = 3;
const END_STR_COL: i32 = 4;

lazy_static! {
    static ref DEFAULT_TITLE: String = "untitled".to_owned();
}

pub struct ChapterEntry<'a> {
    store: &'a gtk::TreeStore,
    iter: &'a gtk::TreeIter,
}

impl<'a> ChapterEntry<'a> {
    pub fn new(store: &'a gtk::TreeStore, iter: &'a gtk::TreeIter) -> ChapterEntry<'a> {
        ChapterEntry {
            store: store,
            iter: iter,
        }
    }

    pub fn title(&self) -> String {
        ChapterEntry::get_title(self.store, self.iter)
    }

    pub fn start(&self) -> u64 {
        ChapterEntry::get_start(self.store, self.iter)
    }

    pub fn start_str(&self) -> String {
        ChapterEntry::get_start_str(self.store, self.iter)
    }

    pub fn start_ts(&self) -> Timestamp {
        Timestamp::from_nano(ChapterEntry::get_start(self.store, self.iter))
    }

    pub fn end(&self) -> u64 {
        ChapterEntry::get_end(self.store, self.iter)
    }

    pub fn end_str(&self) -> String {
        ChapterEntry::get_end_str(self.store, self.iter)
    }

    pub fn end_ts(&self) -> Timestamp {
        Timestamp::from_nano(ChapterEntry::get_end(self.store, self.iter))
    }

    pub fn get_title(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> String {
        store.get_value(iter, TITLE_COL).get::<String>().unwrap()
    }

    pub fn get_start(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> u64 {
        store.get_value(iter, START_COL).get::<u64>().unwrap()
    }

    pub fn get_start_str(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> String {
        store
            .get_value(iter, START_STR_COL)
            .get::<String>()
            .unwrap()
    }

    pub fn get_end(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> u64 {
        store.get_value(iter, END_COL).get::<u64>().unwrap()
    }

    pub fn get_end_str(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> String {
        store.get_value(iter, END_STR_COL).get::<String>().unwrap()
    }
}

pub struct ChapterTreeManager {
    store: gtk::TreeStore,
    iter: Option<gtk::TreeIter>,
    selected_iter: Option<gtk::TreeIter>,
}

impl ChapterTreeManager {
    pub fn new_from(store: gtk::TreeStore) -> Self {
        ChapterTreeManager {
            store: store,
            iter: None,
            selected_iter: None,
        }
    }

    pub fn init_treeview(&self, treeview: &gtk::TreeView) {
        treeview.set_model(Some(&self.store));
        self.add_column(treeview, "Title", TITLE_COL, true, true);
        self.add_column(treeview, "Start", START_STR_COL, false, false);
        self.add_column(treeview, "End", END_STR_COL, false, false);
    }

    fn add_column(
        &self,
        treeview: &gtk::TreeView,
        title: &str,
        col_id: i32,
        can_expand: bool,
        is_editable: bool,
    ) {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);

        let renderer = gtk::CellRendererText::new();
        if is_editable {
            renderer.set_property_editable(true);
            let store_clone = self.store.clone();
            renderer.connect_edited(move |_, tree_path, value| {
                if let Some(iter) = store_clone.get_iter(&tree_path) {
                    store_clone.set_value(&iter, TITLE_COL as u32, &gtk::Value::from(value));
                }
            });
        }

        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text", col_id);
        if can_expand {
            col.set_min_width(70);
            col.set_expand(can_expand);
        }
        treeview.append_column(&col);
    }

    pub fn get_selected_iter(&self) -> Option<gtk::TreeIter> {
        self.selected_iter.clone()
    }

    pub fn get_chapter_at_iter<'a: 'b, 'b>(&'a self, iter: &'a gtk::TreeIter) -> ChapterEntry<'b> {
        ChapterEntry::new(&self.store, iter)
    }

    pub fn get_iter(&self, tree_path: &gtk::TreePath) -> Option<gtk::TreeIter> {
        self.store.get_iter(tree_path)
    }

    pub fn unselect(&mut self) {
        self.selected_iter = None;
    }

    pub fn rewind(&mut self) {
        self.iter = self.store.get_iter_first();
    }

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

    pub fn replace_with(&mut self, chapter_list: &[Chapter]) {
        self.clear();

        for chapter in chapter_list.iter() {
            self.store.insert_with_values(
                None,
                None,
                &[
                    START_COL as u32,
                    END_COL as u32,
                    TITLE_COL as u32,
                    START_STR_COL as u32,
                    END_STR_COL as u32,
                ],
                &[
                    &chapter.start.nano_total,
                    &chapter.end.nano_total,
                    &chapter.get_title().unwrap_or(&DEFAULT_TITLE),
                    &format!("{}", &chapter.start),
                    &format!("{}", chapter.end),
                ],
            );
        }

        self.iter = self.store.get_iter_first();

        self.selected_iter = match self.iter {
            Some(ref iter) => {
                if ChapterEntry::get_start(&self.store, iter) == 0 {
                    Some(iter.clone())
                } else {
                    None
                }
            }
            None => None,
        };
    }

    // Iterate over the chapters and apply func to all elements until the last
    // or until func returns false
    //
    // If first_iter is_some, iterate from first_iter
    pub fn for_each<F>(&self, first_iter: Option<gtk::TreeIter>, mut func: F)
    where
        F: FnMut(ChapterEntry) -> bool, // closure must return true to keep going
    {
        let iter = match first_iter {
            Some(first_iter) => first_iter,
            None => match self.store.get_iter_first() {
                Some(first_iter) => first_iter,
                None => return,
            },
        };

        while func(ChapterEntry::new(&self.store, &iter)) && self.store.iter_next(&iter) {}
    }

    // Update chapter according to the given position
    // Returns (has_changed, prev_selected_iter)
    pub fn update_position(&mut self, position: u64) -> (bool, Option<gtk::TreeIter>) {
        let has_changed = match self.selected_iter {
            Some(ref selected_iter) => {
                if position >= ChapterEntry::get_start(&self.store, selected_iter)
                    && position < ChapterEntry::get_end(&self.store, selected_iter)
                {
                    // regular case: position in current chapter => don't change anything
                    // this check is here to save time in the most frequent case
                    return (false, None);
                }
                // chapter has changed
                true
            }
            None => false,
        };

        let prev_selected_iter = self.selected_iter.take();

        if let Some(iter) = self.iter.take() {
            // not in selected_iter or selected_iter not defined yet => find current chapter
            let mut searching_forward = true;
            while if position >= ChapterEntry::get_start(&self.store, &iter)
                && position < ChapterEntry::get_end(&self.store, &iter)
            {
                // position is in iter
                self.selected_iter = Some(iter.clone());
                self.iter = Some(iter);
                return (true, prev_selected_iter);
            } else if position >= ChapterEntry::get_end(&self.store, &iter) && searching_forward {
                // position is after iter and we were already searching forward
                self.store.iter_next(&iter)
            } else if position < ChapterEntry::get_start(&self.store, &iter) {
                // position before iter
                searching_forward = false;
                if self.store.iter_previous(&iter) {
                    // iter is still valid
                    true
                } else {
                    // before first chapter
                    self.iter = self.store.get_iter_first();
                    return (has_changed, prev_selected_iter);
                }
            } else {
                // in a gap between two chapters
                self.iter = Some(iter);
                return (has_changed, prev_selected_iter);
            } {}

            // passed the end of the last chapter
            // prevent from searching in subsequent calls
            self.iter = None;
        }

        (has_changed, prev_selected_iter)
    }

    pub fn prepare_for_seek(&mut self) {
        if self.iter.is_none() {
            // either there is no chapter or previous position had already passed the end
            // => force scanning of the chapters list in order to set iter back on track
            self.rewind();
        }
    }

    // Returns an iter on the new chapter
    pub fn add_chapter(&mut self, position: u64, duration: u64) -> Option<gtk::TreeIter> {
        let (new_iter, end, end_str) = match self.selected_iter.take() {
            Some(selected_iter) => {
                // a chapter is currently selected
                let (current_start, current_end, current_end_str) = {
                    let selected_chapter = ChapterEntry::new(&self.store, &selected_iter);
                    (
                        selected_chapter.start(),
                        selected_chapter.end(),
                        selected_chapter.end_str(),
                    )
                };

                if current_start != position {
                    // update currently selected chapter end
                    // to match the start of the newly added chapter
                    self.store.set(
                        &selected_iter,
                        &[END_COL as u32, END_STR_COL as u32],
                        &[&position, &Timestamp::format(position, false)],
                    );

                    // insert new chapter after current
                    let new_iter = self.store.insert_after(None, &selected_iter);
                    (new_iter, current_end, current_end_str)
                } else {
                    // attempting to add the new chapter at current position
                    // => restore current state
                    self.selected_iter = Some(selected_iter);
                    return None;
                }
            }
            None => {
                match self.iter.take() {
                    Some(iter) => {
                        // chapters are available, but none is selected:
                        // either position is before the first chapter
                        // or in a gap between two chapters
                        let iter_chapter = ChapterEntry::new(&self.store, &iter);
                        let start = iter_chapter.start();
                        if position > start {
                            panic!(
                                concat!(
                                    "ChapterTreeManager::add_chapter inconsistent position",
                                    " {} with regard to current iter [{}, {}]",
                                ),
                                position,
                                iter_chapter.start(),
                                iter_chapter.end(),
                            );
                        }

                        // iter is next chapter

                        (
                            self.store.insert_before(None, &iter),
                            start,
                            iter_chapter.start_str(),
                        )
                    }
                    None => {
                        // No chapter in iter:
                        // either position is passed the end of last chapter
                        // or there is no chapter
                        let insert_position = match self.store.get_iter_first() {
                                    None => // No chapter yet => inset at the beginning
                                        0i32,
                                    Some(_) => // store contains chapters => insert at the end
                                        -1i32,
                                };
                        (
                            self.store.insert(None, insert_position),
                            duration,
                            Timestamp::format(duration, false),
                        )
                    }
                }
            }
        };

        self.store.set(
            &new_iter,
            &[
                TITLE_COL as u32,
                START_COL as u32,
                START_STR_COL as u32,
                END_COL as u32,
                END_STR_COL as u32,
            ],
            &[
                &*DEFAULT_TITLE,
                &position,
                &Timestamp::format(position, false),
                &end,
                &end_str,
            ],
        );

        self.selected_iter = Some(new_iter.clone());
        self.iter = Some(new_iter.clone());
        Some(new_iter)
    }

    // Returns an iter on the chapter which should be selected, if any
    pub fn remove_selected_chapter(&mut self) -> Option<gtk::TreeIter> {
        match self.selected_iter.take() {
            Some(selected_iter) => {
                let prev_iter = selected_iter.clone();
                let next_selected_iter = if self.store.iter_previous(&prev_iter) {
                    // a previous chapter is available => update its end
                    // with the end of currently selected chapter
                    let selected_chapter = ChapterEntry::new(&self.store, &selected_iter);
                    self.store.set(
                        &prev_iter,
                        &[END_COL as u32, END_STR_COL as u32],
                        &[&selected_chapter.end(), &selected_chapter.end_str()],
                    );

                    Some(prev_iter)
                } else {
                    // no chapter before => nothing to select
                    None
                };

                self.store.remove(&selected_iter);
                self.selected_iter = next_selected_iter.clone();
                match next_selected_iter {
                    None =>
                        // No chapter before => rewind
                        self.rewind(),
                    Some(ref next_selected_iter) => self.iter = Some(next_selected_iter.clone()),
                }
                next_selected_iter
            }
            None => None,
        }
    }
}
<commit_msg>Chapters list: align times right<commit_after>extern crate gtk;
use gtk::prelude::*;

extern crate lazy_static;

use metadata::{Chapter, Timestamp};

const START_COL: i32 = 0;
const END_COL: i32 = 1;
const TITLE_COL: i32 = 2;
const START_STR_COL: i32 = 3;
const END_STR_COL: i32 = 4;

lazy_static! {
    static ref DEFAULT_TITLE: String = "untitled".to_owned();
}

pub struct ChapterEntry<'a> {
    store: &'a gtk::TreeStore,
    iter: &'a gtk::TreeIter,
}

impl<'a> ChapterEntry<'a> {
    pub fn new(store: &'a gtk::TreeStore, iter: &'a gtk::TreeIter) -> ChapterEntry<'a> {
        ChapterEntry {
            store: store,
            iter: iter,
        }
    }

    pub fn title(&self) -> String {
        ChapterEntry::get_title(self.store, self.iter)
    }

    pub fn start(&self) -> u64 {
        ChapterEntry::get_start(self.store, self.iter)
    }

    pub fn start_str(&self) -> String {
        ChapterEntry::get_start_str(self.store, self.iter)
    }

    pub fn start_ts(&self) -> Timestamp {
        Timestamp::from_nano(ChapterEntry::get_start(self.store, self.iter))
    }

    pub fn end(&self) -> u64 {
        ChapterEntry::get_end(self.store, self.iter)
    }

    pub fn end_str(&self) -> String {
        ChapterEntry::get_end_str(self.store, self.iter)
    }

    pub fn end_ts(&self) -> Timestamp {
        Timestamp::from_nano(ChapterEntry::get_end(self.store, self.iter))
    }

    pub fn get_title(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> String {
        store.get_value(iter, TITLE_COL).get::<String>().unwrap()
    }

    pub fn get_start(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> u64 {
        store.get_value(iter, START_COL).get::<u64>().unwrap()
    }

    pub fn get_start_str(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> String {
        store
            .get_value(iter, START_STR_COL)
            .get::<String>()
            .unwrap()
    }

    pub fn get_end(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> u64 {
        store.get_value(iter, END_COL).get::<u64>().unwrap()
    }

    pub fn get_end_str(store: &gtk::TreeStore, iter: &gtk::TreeIter) -> String {
        store.get_value(iter, END_STR_COL).get::<String>().unwrap()
    }
}

pub struct ChapterTreeManager {
    store: gtk::TreeStore,
    iter: Option<gtk::TreeIter>,
    selected_iter: Option<gtk::TreeIter>,
}

impl ChapterTreeManager {
    pub fn new_from(store: gtk::TreeStore) -> Self {
        ChapterTreeManager {
            store: store,
            iter: None,
            selected_iter: None,
        }
    }

    pub fn init_treeview(&self, treeview: &gtk::TreeView) {
        treeview.set_model(Some(&self.store));
        self.add_column(treeview, "Title", TITLE_COL, true, true);
        self.add_column(treeview, "Start", START_STR_COL, false, false);
        self.add_column(treeview, "End", END_STR_COL, false, false);
    }

    fn add_column(
        &self,
        treeview: &gtk::TreeView,
        title: &str,
        col_id: i32,
        can_expand: bool,
        is_editable: bool,
    ) {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);

        let renderer = gtk::CellRendererText::new();
        if is_editable {
            renderer.set_property_editable(true);
            let store_clone = self.store.clone();
            renderer.connect_edited(move |_, tree_path, value| {
                if let Some(iter) = store_clone.get_iter(&tree_path) {
                    store_clone.set_value(&iter, TITLE_COL as u32, &gtk::Value::from(value));
                }
            });
        }

        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text", col_id);
        if can_expand {
            col.set_min_width(70);
            col.set_expand(can_expand);
        } else {
            // align right
            renderer.set_property_xalign(1f32);
        }
        treeview.append_column(&col);
    }

    pub fn get_selected_iter(&self) -> Option<gtk::TreeIter> {
        self.selected_iter.clone()
    }

    pub fn get_chapter_at_iter<'a: 'b, 'b>(&'a self, iter: &'a gtk::TreeIter) -> ChapterEntry<'b> {
        ChapterEntry::new(&self.store, iter)
    }

    pub fn get_iter(&self, tree_path: &gtk::TreePath) -> Option<gtk::TreeIter> {
        self.store.get_iter(tree_path)
    }

    pub fn unselect(&mut self) {
        self.selected_iter = None;
    }

    pub fn rewind(&mut self) {
        self.iter = self.store.get_iter_first();
    }

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

    pub fn replace_with(&mut self, chapter_list: &[Chapter]) {
        self.clear();

        for chapter in chapter_list.iter() {
            self.store.insert_with_values(
                None,
                None,
                &[
                    START_COL as u32,
                    END_COL as u32,
                    TITLE_COL as u32,
                    START_STR_COL as u32,
                    END_STR_COL as u32,
                ],
                &[
                    &chapter.start.nano_total,
                    &chapter.end.nano_total,
                    &chapter.get_title().unwrap_or(&DEFAULT_TITLE),
                    &format!("{}", &chapter.start),
                    &format!("{}", chapter.end),
                ],
            );
        }

        self.iter = self.store.get_iter_first();

        self.selected_iter = match self.iter {
            Some(ref iter) => {
                if ChapterEntry::get_start(&self.store, iter) == 0 {
                    Some(iter.clone())
                } else {
                    None
                }
            }
            None => None,
        };
    }

    // Iterate over the chapters and apply func to all elements until the last
    // or until func returns false
    //
    // If first_iter is_some, iterate from first_iter
    pub fn for_each<F>(&self, first_iter: Option<gtk::TreeIter>, mut func: F)
    where
        F: FnMut(ChapterEntry) -> bool, // closure must return true to keep going
    {
        let iter = match first_iter {
            Some(first_iter) => first_iter,
            None => match self.store.get_iter_first() {
                Some(first_iter) => first_iter,
                None => return,
            },
        };

        while func(ChapterEntry::new(&self.store, &iter)) && self.store.iter_next(&iter) {}
    }

    // Update chapter according to the given position
    // Returns (has_changed, prev_selected_iter)
    pub fn update_position(&mut self, position: u64) -> (bool, Option<gtk::TreeIter>) {
        let has_changed = match self.selected_iter {
            Some(ref selected_iter) => {
                if position >= ChapterEntry::get_start(&self.store, selected_iter)
                    && position < ChapterEntry::get_end(&self.store, selected_iter)
                {
                    // regular case: position in current chapter => don't change anything
                    // this check is here to save time in the most frequent case
                    return (false, None);
                }
                // chapter has changed
                true
            }
            None => false,
        };

        let prev_selected_iter = self.selected_iter.take();

        if let Some(iter) = self.iter.take() {
            // not in selected_iter or selected_iter not defined yet => find current chapter
            let mut searching_forward = true;
            while if position >= ChapterEntry::get_start(&self.store, &iter)
                && position < ChapterEntry::get_end(&self.store, &iter)
            {
                // position is in iter
                self.selected_iter = Some(iter.clone());
                self.iter = Some(iter);
                return (true, prev_selected_iter);
            } else if position >= ChapterEntry::get_end(&self.store, &iter) && searching_forward {
                // position is after iter and we were already searching forward
                self.store.iter_next(&iter)
            } else if position < ChapterEntry::get_start(&self.store, &iter) {
                // position before iter
                searching_forward = false;
                if self.store.iter_previous(&iter) {
                    // iter is still valid
                    true
                } else {
                    // before first chapter
                    self.iter = self.store.get_iter_first();
                    return (has_changed, prev_selected_iter);
                }
            } else {
                // in a gap between two chapters
                self.iter = Some(iter);
                return (has_changed, prev_selected_iter);
            } {}

            // passed the end of the last chapter
            // prevent from searching in subsequent calls
            self.iter = None;
        }

        (has_changed, prev_selected_iter)
    }

    pub fn prepare_for_seek(&mut self) {
        if self.iter.is_none() {
            // either there is no chapter or previous position had already passed the end
            // => force scanning of the chapters list in order to set iter back on track
            self.rewind();
        }
    }

    // Returns an iter on the new chapter
    pub fn add_chapter(&mut self, position: u64, duration: u64) -> Option<gtk::TreeIter> {
        let (new_iter, end, end_str) = match self.selected_iter.take() {
            Some(selected_iter) => {
                // a chapter is currently selected
                let (current_start, current_end, current_end_str) = {
                    let selected_chapter = ChapterEntry::new(&self.store, &selected_iter);
                    (
                        selected_chapter.start(),
                        selected_chapter.end(),
                        selected_chapter.end_str(),
                    )
                };

                if current_start != position {
                    // update currently selected chapter end
                    // to match the start of the newly added chapter
                    self.store.set(
                        &selected_iter,
                        &[END_COL as u32, END_STR_COL as u32],
                        &[&position, &Timestamp::format(position, false)],
                    );

                    // insert new chapter after current
                    let new_iter = self.store.insert_after(None, &selected_iter);
                    (new_iter, current_end, current_end_str)
                } else {
                    // attempting to add the new chapter at current position
                    // => restore current state
                    self.selected_iter = Some(selected_iter);
                    return None;
                }
            }
            None => {
                match self.iter.take() {
                    Some(iter) => {
                        // chapters are available, but none is selected:
                        // either position is before the first chapter
                        // or in a gap between two chapters
                        let iter_chapter = ChapterEntry::new(&self.store, &iter);
                        let start = iter_chapter.start();
                        if position > start {
                            panic!(
                                concat!(
                                    "ChapterTreeManager::add_chapter inconsistent position",
                                    " {} with regard to current iter [{}, {}]",
                                ),
                                position,
                                iter_chapter.start(),
                                iter_chapter.end(),
                            );
                        }

                        // iter is next chapter

                        (
                            self.store.insert_before(None, &iter),
                            start,
                            iter_chapter.start_str(),
                        )
                    }
                    None => {
                        // No chapter in iter:
                        // either position is passed the end of last chapter
                        // or there is no chapter
                        let insert_position = match self.store.get_iter_first() {
                                    None => // No chapter yet => inset at the beginning
                                        0i32,
                                    Some(_) => // store contains chapters => insert at the end
                                        -1i32,
                                };
                        (
                            self.store.insert(None, insert_position),
                            duration,
                            Timestamp::format(duration, false),
                        )
                    }
                }
            }
        };

        self.store.set(
            &new_iter,
            &[
                TITLE_COL as u32,
                START_COL as u32,
                START_STR_COL as u32,
                END_COL as u32,
                END_STR_COL as u32,
            ],
            &[
                &*DEFAULT_TITLE,
                &position,
                &Timestamp::format(position, false),
                &end,
                &end_str,
            ],
        );

        self.selected_iter = Some(new_iter.clone());
        self.iter = Some(new_iter.clone());
        Some(new_iter)
    }

    // Returns an iter on the chapter which should be selected, if any
    pub fn remove_selected_chapter(&mut self) -> Option<gtk::TreeIter> {
        match self.selected_iter.take() {
            Some(selected_iter) => {
                let prev_iter = selected_iter.clone();
                let next_selected_iter = if self.store.iter_previous(&prev_iter) {
                    // a previous chapter is available => update its end
                    // with the end of currently selected chapter
                    let selected_chapter = ChapterEntry::new(&self.store, &selected_iter);
                    self.store.set(
                        &prev_iter,
                        &[END_COL as u32, END_STR_COL as u32],
                        &[&selected_chapter.end(), &selected_chapter.end_str()],
                    );

                    Some(prev_iter)
                } else {
                    // no chapter before => nothing to select
                    None
                };

                self.store.remove(&selected_iter);
                self.selected_iter = next_selected_iter.clone();
                match next_selected_iter {
                    None =>
                        // No chapter before => rewind
                        self.rewind(),
                    Some(ref next_selected_iter) => self.iter = Some(next_selected_iter.clone()),
                }
                next_selected_iter
            }
            None => None,
        }
    }
}
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::hir::intravisit::FnKind;
use rustc::lint::*;
use rustc::ty::{self, TypeFoldable};
use rustc::traits;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use syntax::ast::NodeId;
use syntax_pos::Span;
use syntax::errors::DiagnosticBuilder;
use utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
            snippet, span_lint_and_then};
use std::collections::{HashMap, HashSet};

/// **What it does:** Checks for functions taking arguments by value, but not
/// consuming them in its
/// body.
///
/// **Why is this bad?** Taking arguments by reference is more flexible and can
/// sometimes avoid
/// unnecessary allocations.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
/// ```rust
/// fn foo(v: Vec<i32>) {
///     assert_eq!(v.len(), 42);
/// }
/// ```
declare_lint! {
    pub NEEDLESS_PASS_BY_VALUE,
    Warn,
    "functions taking arguments by value, but not consuming them in its body"
}

pub struct NeedlessPassByValue;

impl LintPass for NeedlessPassByValue {
    fn get_lints(&self) -> LintArray {
        lint_array![NEEDLESS_PASS_BY_VALUE]
    }
}

macro_rules! need {
    ($e: expr) => { if let Some(x) = $e { x } else { return; } };
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        node_id: NodeId,
    ) {
        if in_macro(span) {
            return;
        }

        match kind {
            FnKind::ItemFn(.., attrs) => for a in attrs {
                if_let_chain!{[
                    a.meta_item_list().is_some(),
                    let Some(name) = a.name(),
                    name == "proc_macro_derive",
                ], {
                    return;
                }}
            },
            _ => return,
        }

        // Allows these to be passed by value.
        let fn_trait = need!(cx.tcx.lang_items().fn_trait());
        let asref_trait = need!(get_trait_def_id(cx, &paths::ASREF_TRAIT));
        let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));

        let fn_def_id = cx.tcx.hir.local_def_id(node_id);

        let preds: Vec<ty::Predicate> = {
            traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
                .filter(|p| !p.is_global())
                .collect()
        };

        // Collect moved variables and spans which will need dereferencings from the
        // function body.
        let MovedVariablesCtxt {
            moved_vars,
            spans_need_deref,
            ..
        } = {
            let mut ctx = MovedVariablesCtxt::new(cx);
            let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
            euv::ExprUseVisitor::new(&mut ctx, cx.tcx, cx.param_env, region_scope_tree, cx.tables).consume_body(body);
            ctx
        };

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        for ((input, &ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) {
            // Determines whether `ty` implements `Borrow<U>` (U != ty) specifically.
            // This is needed due to the `Borrow<T> for T` blanket impl.
            let implements_borrow_trait = preds
                .iter()
                .filter_map(|pred| if let ty::Predicate::Trait(ref poly_trait_ref) = *pred {
                    Some(poly_trait_ref.skip_binder())
                } else {
                    None
                })
                .filter(|tpred| tpred.def_id() == borrow_trait && tpred.self_ty() == ty)
                .any(|tpred| {
                    tpred
                        .input_types()
                        .nth(1)
                        .expect("Borrow trait must have an parameter") != ty
                });

            if_let_chain! {[
                !is_self(arg),
                !ty.is_mutable_pointer(),
                !is_copy(cx, ty),
                !implements_trait(cx, ty, fn_trait, &[]),
                !implements_trait(cx, ty, asref_trait, &[]),
                !implements_borrow_trait,

                let PatKind::Binding(mode, canonical_id, ..) = arg.pat.node,
                !moved_vars.contains(&canonical_id),
            ], {
                // Note: `toplevel_ref_arg` warns if `BindByRef`
                if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
                    continue;
                }

                // Suggestion logic
                let sugg = |db: &mut DiagnosticBuilder| {
                    let deref_span = spans_need_deref.get(&canonical_id);
                    if_let_chain! {[
                        match_type(cx, ty, &paths::VEC),
                        let TyPath(QPath::Resolved(_, ref path)) = input.node,
                        let Some(elem_ty) = path.segments.iter()
                            .find(|seg| seg.name == "Vec")
                            .and_then(|ref ps| ps.parameters.as_ref())
                            .map(|params| &params.types[0]),
                    ], {
                        let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
                        db.span_suggestion(input.span,
                                        "consider changing the type to",
                                        slice_ty);
                        assert!(deref_span.is_none());
                        return; // `Vec` and `String` cannot be destructured - no need for `*` suggestion
                    }}

                    if match_type(cx, ty, &paths::STRING) {
                        db.span_suggestion(input.span,
                                           "consider changing the type to",
                                           "&str".to_string());
                        assert!(deref_span.is_none());
                        return;
                    }

                    let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];

                    // Suggests adding `*` to dereference the added reference.
                    if let Some(deref_span) = deref_span {
                        spans.extend(deref_span.iter().cloned()
                                     .map(|span| (span, format!("*{}", snippet(cx, span, "<expr>")))));
                        spans.sort_by_key(|&(span, _)| span);
                    }
                    multispan_sugg(db, "consider taking a reference instead".to_string(), spans);
                };

                span_lint_and_then(cx,
                          NEEDLESS_PASS_BY_VALUE,
                          input.span,
                          "this argument is passed by value, but not consumed in the function body",
                          sugg);
            }}
        }
    }
}

struct MovedVariablesCtxt<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    moved_vars: HashSet<NodeId>,
    /// Spans which need to be prefixed with `*` for dereferencing the
    /// suggested additional
    /// reference.
    spans_need_deref: HashMap<NodeId, HashSet<Span>>,
}

impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx: cx,
            moved_vars: HashSet::new(),
            spans_need_deref: HashMap::new(),
        }
    }

    fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if let mc::Categorization::Local(vid) = cmt.cat {
            self.moved_vars.insert(vid);
        }
    }

    fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if_let_chain! {[
            let mc::Categorization::Local(vid) = cmt.cat,
        ], {
            let mut id = matched_pat.id;
            loop {
                let parent = self.cx.tcx.hir.get_parent_node(id);
                if id == parent {
                    // no parent
                    return;
                }
                id = parent;

                if let Some(node) = self.cx.tcx.hir.find(id) {
                    match node {
                        map::Node::NodeExpr(e) => {
                            // `match` and `if let`
                            if let ExprMatch(ref c, ..) = e.node {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(c.span);
                            }
                        }

                        map::Node::NodeStmt(s) => {
                            // `let <pat> = x;`
                            if_let_chain! {[
                                let StmtDecl(ref decl, _) = s.node,
                                let DeclLocal(ref local) = decl.node,
                            ], {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(local.init
                                        .as_ref()
                                        .map(|e| e.span)
                                        .expect("`let` stmt without init aren't caught by match_pat"));
                            }}
                        }

                        _ => {}
                    }
                }
            }
        }}
    }
}

impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_id, consume_span, cmt);
        }
    }

    fn matched_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::MatchMode) {
        if let euv::MatchMode::MovingMatch = mode {
            self.move_common(matched_pat.id, matched_pat.span, cmt);
        } else {
            self.non_moving_pat(matched_pat, cmt);
        }
    }

    fn consume_pat(&mut self, consume_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_pat.id, consume_pat.span, cmt);
        }
    }

    fn borrow(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {}

    fn mutate(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: euv::MutateMode) {}

    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
}

fn unwrap_downcast_or_interior(mut cmt: mc::cmt) -> mc::cmt {
    loop {
        match cmt.cat.clone() {
            mc::Categorization::Downcast(c, _) | mc::Categorization::Interior(c, _) => {
                cmt = c;
            },
            _ => return cmt,
        }
    }
}
<commit_msg>Fix dogfood needless-borrow<commit_after>use rustc::hir::*;
use rustc::hir::intravisit::FnKind;
use rustc::lint::*;
use rustc::ty::{self, TypeFoldable};
use rustc::traits;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use syntax::ast::NodeId;
use syntax_pos::Span;
use syntax::errors::DiagnosticBuilder;
use utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
            snippet, span_lint_and_then};
use std::collections::{HashMap, HashSet};

/// **What it does:** Checks for functions taking arguments by value, but not
/// consuming them in its
/// body.
///
/// **Why is this bad?** Taking arguments by reference is more flexible and can
/// sometimes avoid
/// unnecessary allocations.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
/// ```rust
/// fn foo(v: Vec<i32>) {
///     assert_eq!(v.len(), 42);
/// }
/// ```
declare_lint! {
    pub NEEDLESS_PASS_BY_VALUE,
    Warn,
    "functions taking arguments by value, but not consuming them in its body"
}

pub struct NeedlessPassByValue;

impl LintPass for NeedlessPassByValue {
    fn get_lints(&self) -> LintArray {
        lint_array![NEEDLESS_PASS_BY_VALUE]
    }
}

macro_rules! need {
    ($e: expr) => { if let Some(x) = $e { x } else { return; } };
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        node_id: NodeId,
    ) {
        if in_macro(span) {
            return;
        }

        match kind {
            FnKind::ItemFn(.., attrs) => for a in attrs {
                if_let_chain!{[
                    a.meta_item_list().is_some(),
                    let Some(name) = a.name(),
                    name == "proc_macro_derive",
                ], {
                    return;
                }}
            },
            _ => return,
        }

        // Allows these to be passed by value.
        let fn_trait = need!(cx.tcx.lang_items().fn_trait());
        let asref_trait = need!(get_trait_def_id(cx, &paths::ASREF_TRAIT));
        let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));

        let fn_def_id = cx.tcx.hir.local_def_id(node_id);

        let preds: Vec<ty::Predicate> = {
            traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
                .filter(|p| !p.is_global())
                .collect()
        };

        // Collect moved variables and spans which will need dereferencings from the
        // function body.
        let MovedVariablesCtxt {
            moved_vars,
            spans_need_deref,
            ..
        } = {
            let mut ctx = MovedVariablesCtxt::new(cx);
            let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
            euv::ExprUseVisitor::new(&mut ctx, cx.tcx, cx.param_env, region_scope_tree, cx.tables).consume_body(body);
            ctx
        };

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        for ((input, &ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) {
            // Determines whether `ty` implements `Borrow<U>` (U != ty) specifically.
            // This is needed due to the `Borrow<T> for T` blanket impl.
            let implements_borrow_trait = preds
                .iter()
                .filter_map(|pred| if let ty::Predicate::Trait(ref poly_trait_ref) = *pred {
                    Some(poly_trait_ref.skip_binder())
                } else {
                    None
                })
                .filter(|tpred| tpred.def_id() == borrow_trait && tpred.self_ty() == ty)
                .any(|tpred| {
                    tpred
                        .input_types()
                        .nth(1)
                        .expect("Borrow trait must have an parameter") != ty
                });

            if_let_chain! {[
                !is_self(arg),
                !ty.is_mutable_pointer(),
                !is_copy(cx, ty),
                !implements_trait(cx, ty, fn_trait, &[]),
                !implements_trait(cx, ty, asref_trait, &[]),
                !implements_borrow_trait,

                let PatKind::Binding(mode, canonical_id, ..) = arg.pat.node,
                !moved_vars.contains(&canonical_id),
            ], {
                // Note: `toplevel_ref_arg` warns if `BindByRef`
                if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
                    continue;
                }

                // Suggestion logic
                let sugg = |db: &mut DiagnosticBuilder| {
                    let deref_span = spans_need_deref.get(&canonical_id);
                    if_let_chain! {[
                        match_type(cx, ty, &paths::VEC),
                        let TyPath(QPath::Resolved(_, ref path)) = input.node,
                        let Some(elem_ty) = path.segments.iter()
                            .find(|seg| seg.name == "Vec")
                            .and_then(|ps| ps.parameters.as_ref())
                            .map(|params| &params.types[0]),
                    ], {
                        let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
                        db.span_suggestion(input.span,
                                        "consider changing the type to",
                                        slice_ty);
                        assert!(deref_span.is_none());
                        return; // `Vec` and `String` cannot be destructured - no need for `*` suggestion
                    }}

                    if match_type(cx, ty, &paths::STRING) {
                        db.span_suggestion(input.span,
                                           "consider changing the type to",
                                           "&str".to_string());
                        assert!(deref_span.is_none());
                        return;
                    }

                    let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];

                    // Suggests adding `*` to dereference the added reference.
                    if let Some(deref_span) = deref_span {
                        spans.extend(deref_span.iter().cloned()
                                     .map(|span| (span, format!("*{}", snippet(cx, span, "<expr>")))));
                        spans.sort_by_key(|&(span, _)| span);
                    }
                    multispan_sugg(db, "consider taking a reference instead".to_string(), spans);
                };

                span_lint_and_then(cx,
                          NEEDLESS_PASS_BY_VALUE,
                          input.span,
                          "this argument is passed by value, but not consumed in the function body",
                          sugg);
            }}
        }
    }
}

struct MovedVariablesCtxt<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    moved_vars: HashSet<NodeId>,
    /// Spans which need to be prefixed with `*` for dereferencing the
    /// suggested additional
    /// reference.
    spans_need_deref: HashMap<NodeId, HashSet<Span>>,
}

impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx: cx,
            moved_vars: HashSet::new(),
            spans_need_deref: HashMap::new(),
        }
    }

    fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if let mc::Categorization::Local(vid) = cmt.cat {
            self.moved_vars.insert(vid);
        }
    }

    fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if_let_chain! {[
            let mc::Categorization::Local(vid) = cmt.cat,
        ], {
            let mut id = matched_pat.id;
            loop {
                let parent = self.cx.tcx.hir.get_parent_node(id);
                if id == parent {
                    // no parent
                    return;
                }
                id = parent;

                if let Some(node) = self.cx.tcx.hir.find(id) {
                    match node {
                        map::Node::NodeExpr(e) => {
                            // `match` and `if let`
                            if let ExprMatch(ref c, ..) = e.node {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(c.span);
                            }
                        }

                        map::Node::NodeStmt(s) => {
                            // `let <pat> = x;`
                            if_let_chain! {[
                                let StmtDecl(ref decl, _) = s.node,
                                let DeclLocal(ref local) = decl.node,
                            ], {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(local.init
                                        .as_ref()
                                        .map(|e| e.span)
                                        .expect("`let` stmt without init aren't caught by match_pat"));
                            }}
                        }

                        _ => {}
                    }
                }
            }
        }}
    }
}

impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_id, consume_span, cmt);
        }
    }

    fn matched_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::MatchMode) {
        if let euv::MatchMode::MovingMatch = mode {
            self.move_common(matched_pat.id, matched_pat.span, cmt);
        } else {
            self.non_moving_pat(matched_pat, cmt);
        }
    }

    fn consume_pat(&mut self, consume_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_pat.id, consume_pat.span, cmt);
        }
    }

    fn borrow(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {}

    fn mutate(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: euv::MutateMode) {}

    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
}

fn unwrap_downcast_or_interior(mut cmt: mc::cmt) -> mc::cmt {
    loop {
        match cmt.cat.clone() {
            mc::Categorization::Downcast(c, _) | mc::Categorization::Interior(c, _) => {
                cmt = c;
            },
            _ => return cmt,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, Result};
use functional_tests::{
    compiler::{Compiler, ScriptOrModule},
    testsuite,
};
use libra_types::account_address::AccountAddress as LibraAddress;
use move_lang::test_utils::stdlib_files;
use move_lang::{move_compile_no_report, shared::Address, to_bytecode::translate::CompiledUnit};
use std::{convert::TryFrom, io::Write, path::Path};
use tempfile::NamedTempFile;

struct MoveSourceCompiler {
    deps: Vec<String>,
    temp_files: Vec<NamedTempFile>,
}

impl MoveSourceCompiler {
    fn new(stdlib_modules_file_names: Vec<String>) -> Self {
        MoveSourceCompiler {
            deps: stdlib_modules_file_names,
            temp_files: vec![],
        }
    }
}

impl Compiler for MoveSourceCompiler {
    /// Compile a transaction script or module.
    fn compile<Logger: FnMut(String) -> ()>(
        &mut self,
        _log: Logger,
        address: LibraAddress,
        input: &str,
    ) -> Result<ScriptOrModule> {
        let cur_file = NamedTempFile::new()?;
        cur_file.reopen()?.write_all(input.as_bytes())?;
        let cur_path = cur_file.path().to_str().unwrap().to_owned();
        self.temp_files.push(cur_file);

        let targets = &vec![cur_path.clone()];
        let sender = Some(Address::try_from(address.as_ref()).unwrap());
        let (files, units_or_errors) = move_compile_no_report(targets, &self.deps, sender)?;
        let unit = match units_or_errors {
            Err(errors) => {
                let error_buffer = move_lang::errors::report_errors_to_buffer(files, errors);
                bail!("{}", String::from_utf8(error_buffer).unwrap())
            }
            Ok(mut units) => {
                let len = units.len();
                if len != 1 {
                    bail!("Invalid input. Expected 1 compiled unit but got {}", len)
                }
                units.pop().unwrap()
            }
        };

        Ok(match unit {
            CompiledUnit::Script(_, compiled_script) => ScriptOrModule::Script(compiled_script),
            CompiledUnit::Module(_, compiled_module) => {
                self.deps.push(cur_path);
                ScriptOrModule::Module(compiled_module)
            }
        })
    }
}

fn functional_testsuite(path: &Path) -> datatest_stable::Result<()> {
    let compiler = MoveSourceCompiler::new(stdlib_files());
    testsuite::functional_tests(compiler, path)
}

datatest_stable::harness!(functional_testsuite, "tests/functional", r".*\.move");
<commit_msg>[move source language] Quick Functional Test Workaround<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, Result};
use functional_tests::{
    compiler::{Compiler, ScriptOrModule},
    testsuite,
};
use libra_types::account_address::AccountAddress as LibraAddress;
use move_lang::test_utils::stdlib_files;
use move_lang::{move_compile_no_report, shared::Address, to_bytecode::translate::CompiledUnit};
use std::{convert::TryFrom, io::Write, path::Path};
use tempfile::NamedTempFile;

struct MoveSourceCompiler {
    deps: Vec<String>,
    temp_files: Vec<NamedTempFile>,
}

impl MoveSourceCompiler {
    fn new(stdlib_modules_file_names: Vec<String>) -> Self {
        MoveSourceCompiler {
            deps: stdlib_modules_file_names,
            temp_files: vec![],
        }
    }
}

impl Compiler for MoveSourceCompiler {
    /// Compile a transaction script or module.
    fn compile<Logger: FnMut(String) -> ()>(
        &mut self,
        _log: Logger,
        address: LibraAddress,
        input: &str,
    ) -> Result<ScriptOrModule> {
        let cur_file = NamedTempFile::new()?;
        let sender_addr = Address::try_from(address.as_ref()).unwrap();
        cur_file.reopen()?.write_all(input.as_bytes())?;
        let cur_path = cur_file.path().to_str().unwrap().to_owned();

        let targets = &vec![cur_path.clone()];
        let sender = Some(sender_addr);
        let (files, units_or_errors) = move_compile_no_report(targets, &self.deps, sender)?;
        let unit = match units_or_errors {
            Err(errors) => {
                let error_buffer = move_lang::errors::report_errors_to_buffer(files, errors);
                bail!("{}", String::from_utf8(error_buffer).unwrap())
            }
            Ok(mut units) => {
                let len = units.len();
                if len != 1 {
                    bail!("Invalid input. Expected 1 compiled unit but got {}", len)
                }
                units.pop().unwrap()
            }
        };

        Ok(match unit {
            CompiledUnit::Script(_, compiled_script) => ScriptOrModule::Script(compiled_script),
            CompiledUnit::Module(_, compiled_module) => {
                let input = format!("address {}:\n{}", sender_addr, input);
                cur_file.reopen()?.write_all(input.as_bytes())?;
                self.temp_files.push(cur_file);
                self.deps.push(cur_path);
                ScriptOrModule::Module(compiled_module)
            }
        })
    }
}

fn functional_testsuite(path: &Path) -> datatest_stable::Result<()> {
    let compiler = MoveSourceCompiler::new(stdlib_files());
    testsuite::functional_tests(compiler, path)
}

datatest_stable::harness!(functional_testsuite, "tests/functional", r".*\.move");
<|endoftext|>