<commit_before>extern crate bitflags;
extern crate gnutls;

use gnutls::creds::{Cert, CredType};
use gnutls::{
    init,
    deinit,
    CertVerifyFlags,
    Session
};

use std::io::prelude::*;
use std::os::unix::io::AsRawFd;
use std::net::TcpStream;

fn main() {
    match init() {
        Ok(_) => {},
        Err(_) => panic!("could not initialize.")
    };

    let hostname: &'static str = "localhost";
    let mut creds: Cert = Cert::new().unwrap();
    let mut session: Session = Session::new(gnutls::GNUTLS_CLIENT).unwrap();

    if creds.x509_set_trust_file("../../gnutls/tests/ca.cert.pem", None).err() != None {
        panic!("Error: couldn't set the trust file.");
    }

    if creds.x509_set_key_file("../../gnutls/tests/ca.cert.pem",
                               "../../gnutls/tests/ca.noenckey.pem", None).err() != None {
        panic!("Error: couldn't set the keyfile.");
    }

    match session.set_priority(None) {
        Err(e) => panic!("{}", e),
        Ok(_) => {}
    };

    if session.set_creds(CredType::GNUTLS_CRD_CERTIFICATE, &mut creds) .err() != None {
        panic!("Error: could not set the session credentials.");
    }

    session.set_verify_cert(hostname,
                            Some(CertVerifyFlags::GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT));

    let mut stream = match TcpStream::connect("bheesham.com:443") {
        Err(e) => panic!("{}", e),
        Ok(s) => s
    };

    session.set_fd(stream.as_raw_fd());
    session.handshake_timeout(None);

    match session.handshake() {
        Ok(_) => println!("Established a connection!"),
        Err(e) => panic!("Error: {}", e)
    };

    let _ = stream.write("GET / HTTP/1.0\n\n".as_bytes()).unwrap();

    let mut res: String = String::new();
    let _ = stream.read_to_string(&mut res).unwrap();
    println!("{}", res);

    deinit();
}
<commit_msg>Use x509_set_system_trust() in the example<commit_after>extern crate bitflags;
extern crate gnutls;

use gnutls::creds::{Cert, CredType};
use gnutls::{
    init,
    deinit,
    CertVerifyFlags,
    Session
};

use std::io::prelude::*;
use std::os::unix::io::AsRawFd;
use std::net::TcpStream;

fn main() {
    match init() {
        Ok(_) => {},
        Err(_) => panic!("could not initialize.")
    };

    let hostname: &'static str = "localhost";
    let mut creds: Cert = Cert::new().unwrap();
    let mut session: Session = Session::new(gnutls::GNUTLS_CLIENT).unwrap();

    if creds.x509_set_system_trust().err() != None {
        panic!("Error: couldn't set system trust.");
    }

    if creds.x509_set_key_file("../../gnutls/tests/ca.cert.pem",
                               "../../gnutls/tests/ca.noenckey.pem", None).err() != None {
        panic!("Error: couldn't set the keyfile.");
    }

    match session.set_priority(None) {
        Err(e) => panic!("{}", e),
        Ok(_) => {}
    };

    if session.set_creds(CredType::GNUTLS_CRD_CERTIFICATE, &mut creds) .err() != None {
        panic!("Error: could not set the session credentials.");
    }

    session.set_verify_cert(hostname,
                            Some(CertVerifyFlags::GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT));

    let mut stream = match TcpStream::connect("bheesham.com:443") {
        Err(e) => panic!("{}", e),
        Ok(s) => s
    };

    session.set_fd(stream.as_raw_fd());
    session.handshake_timeout(None);

    match session.handshake() {
        Ok(_) => println!("Established a connection!"),
        Err(e) => panic!("Error: {}", e)
    };

    let _ = stream.write("GET / HTTP/1.0\n\n".as_bytes()).unwrap();

    let mut res: String = String::new();
    let _ = stream.read_to_string(&mut res).unwrap();
    println!("{}", res);

    deinit();
}
<|endoftext|>


<commit_before>extern crate polygon;
extern crate vcdim;

#[cfg(feature = "print_info")]
use polygon::generate::Mode;
#[cfg(feature = "print_info")]
use vcdim::*;

/// Computes the VC-Dimension of some randomly generated polygons
/// and prints statistics about how many steps are saved compared
/// to the naive algorithm.
#[cfg(feature = "print_info")]
fn main() {
    let mut args = std::env::args().skip(1);
    let n = if let Some(n) = args.next() {
        n.parse().expect("n must be an positive integer")
    } else { 20 };
    let count = if let Some(cnt) = args.next() {
        cnt.parse().expect("count must be an positive integer")
    } else { 10 };
    let default_gen_mode = Mode::QuickStarLike;
    let gen_mode = if let Some(m) = args.next() {
        if m.starts_with("--mode=") {
            match &m[7..] {
                "2opt" => Mode::TwoOptLike,
                "quickstar" => Mode::QuickStarLike,
                _ => {
                    println!("Generation mode not recognised: {}\nPossible Values: 2opt, quickstar", &m[7..]);
                    return;
                }
            }
        } else {
            println!("Unrecognised argument: {}", m);
            return;
        }
    } else { default_gen_mode };

    let mut vcd = VcDim::with_random_polygon(n, gen_mode);

    for _ in 0..count {
        let _ = vcd.vc_dimension();
        vcd.randomize_polygon(gen_mode)
    }
}

#[cfg(not(feature = "print_info"))]
fn main() {
    println!("WARNING: This does nothing if the feature `print_info` is disabled.");
    println!("         Please enable this feature.");
    return;
}
<commit_msg>improve example `compute_savings`<commit_after>extern crate polygon;
extern crate vcdim;

#[cfg(feature = "print_info")]
use polygon::generate::Mode;
#[cfg(feature = "print_info")]
use vcdim::*;

/// Computes the VC-Dimension of some randomly generated polygons
/// and prints statistics about how many steps are saved compared
/// to the naive algorithm.
#[cfg(feature = "print_info")]
fn main() {
    let mut args = std::env::args().skip(1);
    let n = if let Some(n) = args.next() {
        n.parse().expect("n must be an positive integer")
    } else { 20 };
    let count = if let Some(cnt) = args.next() {
        cnt.parse().expect("count must be an positive integer")
    } else { 10 };
    let default_gen_mode = Mode::QuickStarLike;
    let gen_mode = if let Some(m) = args.next() {
        if m.starts_with("--mode=") {
            match &m[7..] {
                "2opt" => Mode::TwoOptLike,
                "quickstar" => Mode::QuickStarLike,
                _ => {
                    println!("Generation mode not recognised: {}\nPossible Values: 2opt, quickstar", &m[7..]);
                    return;
                }
            }
        } else {
            println!("Unrecognised argument: {}", m);
            return;
        }
    } else { default_gen_mode };

    let mut vcd = VcDim::with_random_polygon(n, gen_mode);

    for i in 0..count {
        let vc_dim = vcd.vc_dimension();
        if vc_dim >= 5 {
            vcd.export_ipe(std::fs::File::create(format!("./vc{}-n{}_{:03}.ipe", vc_dim, n, i)).unwrap(), 1f64).unwrap();
        }
        vcd.randomize_polygon(gen_mode)
    }
}

#[cfg(not(feature = "print_info"))]
fn main() {
    println!("WARNING: This does nothing if the feature `print_info` is disabled.");
    println!("         Please enable this feature.");
    println!("");
    println!("Example invocation:");
    println!("cargo run --release --example compute_savings --features print_info -- 10 5");
    return;
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::cmp::{max, min};
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    pub fn read_vec(len: usize) -> Vec<String> {
        let mut vec = Vec::new();
        while vec.len() < len {
            let line = read_line();
            for word in line.split_whitespace() {
                vec.push(word.to_owned());
            }
        }
        assert!(vec.len() == len);
        vec
    }
}

#[cfg(test)]
mod tests {
    #[test]
    pub fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }
}
<commit_msg>Add Rev (polyfill for std::cmp::Reverse)<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use procon::*;
use std::cmp::{max, min};
use std::collections::*;
use std::ops::*;
use std::*;

pub fn main() {
    return;
}

pub mod procon {
    use std;
    use std::cmp::*;
    use std::collections::*;
    use std::io;
    use std::mem;
    use std::str::FromStr;

    pub fn read_line() -> String {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim_right().to_owned()
    }

    pub fn read_words<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        T::Err: std::fmt::Debug,
    {
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.split_whitespace()
            .map(|word| T::from_str(word).unwrap())
            .collect()
    }

    pub fn read_vec(len: usize) -> Vec<String> {
        let mut vec = Vec::new();
        while vec.len() < len {
            let line = read_line();
            for word in line.split_whitespace() {
                vec.push(word.to_owned());
            }
        }
        assert!(vec.len() == len);
        vec
    }

    // Polyfill
    #[derive(PartialEq, Eq, Clone, Debug)]
    pub struct Rev<T>(pub T);

    impl<T: PartialOrd> PartialOrd for Rev<T> {
        fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
            other.0.partial_cmp(&self.0)
        }
    }

    impl<T: Ord> Ord for Rev<T> {
        fn cmp(&self, other: &Rev<T>) -> Ordering {
            other.0.cmp(&self.0)
        }
    }
}

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

    #[test]
    pub fn test_ok() {
        assert_eq!(7, 1 + 2 * 3);
    }

    #[test]
    pub fn test_rev() {
        let mut v: Vec<Rev<i32>> = vec![3, 1, 4, 1, 5, 9, 2]
            .into_iter()
            .map(|x| Rev(x))
            .collect::<Vec<_>>();
        v.sort();
        let v = v.into_iter().map(|Rev(x)| x).collect::<Vec<_>>();
        assert_eq!(vec![9, 5, 4, 3, 2, 1, 1], v);
    }
}
<|endoftext|>


<commit_before>
extern crate rdkafka;
use rdkafka::producer::{Producer, ProducerConfig, Record};

fn main() {
    let topic_name = "test-topic".to_string();
    let brokers = vec!["localhost:9042".to_string()];
    let config = ProducerConfig::new(topic_name, brokers)
        .ack_timeout_seconds(23)
        .build();

    println!("{:?}", config);

    let producer = Producer::new(config);

    let record = Record {
        key: "key".to_string(),
        payload: "data".to_string(),
    };

    producer.send(record);
}
<commit_msg>Formatting<commit_after>extern crate rdkafka;
use rdkafka::producer::{Producer, ProducerConfig, Record};

fn main() {
    let topic_name = "test-topic".to_string();
    let brokers = vec!["localhost:9042".to_string()];

    let config = ProducerConfig::new(topic_name, brokers)
        .ack_timeout_seconds(23)
        .build();

    println!("{:?}", config);

    let producer = Producer::new(config);

    let record = Record {
        key: "key".to_string(),
        payload: "data".to_string(),
    };

    producer.send(record);

    // Destroy ??
    // Manual or on impl Drop?
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use capnp_rpc::ez_rpc::EzRpcClient;
use capnp_rpc::rpc::{InitParams, WaitForContent};
use calculator_capnp::Calculator;

pub fn main() {
    let args = std::os::args();
    if args.len() != 3 {
        println!("usage: {} client <server address>", args[0]);
        return;
    }

    let mut rpc_client = EzRpcClient::new(args[2]);

    let calculator_client : Calculator::Client  = rpc_client.import_cap("calculator");

    {
        let mut req = calculator_client.evaluate_request();
        {
            let params = req.init_params();
            let exp = params.init_expression();
            exp.set_literal(123.45);
        }
        let mut res = req.send();
        let value = {
            let results = res.wait();
            results.get_value()
        };

        let mut result = value.read_request().send();
        println!("the value is: {}", result.wait().get_value());
    }

    {
        let mut req = calculator_client.evaluate_request();
        {
            let params = req.init_params();
            let exp = params.init_expression();
            exp.set_literal(55.5);
        }
        let res = req.send();
        let mut result = res.pipeline.get_value().read_request().send();
        let answer = result.wait().get_value();
        println!("the value is: {}", answer);
    }

    rpc_client.netcat.wait();
}
<commit_msg>more in the calculator client<commit_after>/*
 * Copyright (c) 2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use capnp_rpc::ez_rpc::EzRpcClient;
use capnp_rpc::rpc::{InitParams, WaitForContent};
use calculator_capnp::Calculator;

pub fn main() {
    let args = std::os::args();
    if args.len() != 3 {
        println!("usage: {} client <server address>", args[0]);
        return;
    }

    let mut rpc_client = EzRpcClient::new(args[2]);

    let calculator : Calculator::Client  = rpc_client.import_cap("calculator");

    {
        let mut req = calculator.evaluate_request();
        {
            let params = req.init_params();
            let exp = params.init_expression();
            exp.set_literal(123.45);
        }
        let mut res = req.send();
        let value = {
            let results = res.wait();
            results.get_value()
        };

        let mut result = value.read_request().send();
        println!("the value is: {}", result.wait().get_value());
    }

    {
        println!("Evaluating a literal... ");

        let mut request = calculator.evaluate_request();
        request.init_params().get_expression().set_literal(123.0);

        let eval_promise = request.send();

        let mut read_promise = eval_promise.pipeline.get_value().read_request().send();

        let response = read_promise.wait();
        assert_eq!(response.get_value(), 123.0);

        println!("PASS")
    }

    {
        println!("Using add and subtract... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init_params().set_op(Calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let subtract = {
            let mut request = calculator.get_operator_request();
            request.init_params().set_op(Calculator::Operator::Subtract);
            request.send().pipeline.get_func()
        };

        let mut request = calculator.evaluate_request();

        let subtract_call = request.init_params().get_expression().init_call();
        // subtract_call.set_function(subtract);
    }

    rpc_client.netcat.wait();
}
<|endoftext|>


<commit_before>//! This package was automatically generated with [`rust-bindgen`][1] and as such was not
//! user-generated.
//!
//! The functions contained are expected to be used with [`fitsio`][2], a high level API wrapper
//! around the low level direct C-bindings, though the bindings are complete enough to be usable.
//!
//! This code will not be directly documented, and so users should refer to the [`fitsio` C
//! documentation][3] for usage.
//!
//! ## Note about function names
//!
//! Unfortunately we must use fits short names throughout. The C-api exposes long names for
//! functions which are more descriptive, for example `fits_open_file` instead of `ffopen`, but the
//! symbols available in the library have only short names, and the long names are merely
//! preprocessor definitions.
//!
//! ## Examples
//!
//! ```rust
//! use std::ptr;
//! use std::ffi;
//! # use fitsio_sys_bindgen as fitsio_sys;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let filename = ffi::CString::new("!/tmp/test.fits").unwrap();
//! let mut fptr = ptr::null_mut();
//! let mut status = 0;
//!
//! unsafe {
//!     // Create a new file, clobbering any pre-existing file
//!     fitsio_sys::ffinit(&mut fptr as *mut *mut _,
//!         filename.as_ptr(),
//!         &mut status);
//!
//!     // Add an empty primary HDU
//!     fitsio_sys::ffphps(fptr, 8, 0, ptr::null_mut(), &mut status);
//!
//!     // Finally close the file
//!     fitsio_sys::ffclos(fptr, &mut status);
//! }
//!
//! assert_eq!(status, 0);
//! # Ok(())
//! # }
//! ```
//!
//! [1]: https://github.com/servo/rust-bindgen
//! [2]: https://crates.io/crates/fitsio
//! [3]: http://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/cfitsio.html

#![allow(
    non_upper_case_globals,
    non_camel_case_types,
    non_snake_case,
    improper_ctypes
)]
// Prevent clippy from throwing errors in generated code
#![allow(
    clippy::unreadable_literal,
    clippy::transmute_ptr_to_ptr,
    clippy::redundant_static_lifetimes,
    clippy::missing_safety_doc,
    clippy::useless_transmute,
    clippy::trivially_copy_pass_by_ref,
    clippy::too_many_arguments,
    clippy::should_implement_trait
)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(test)]
mod test {
    use super::*;
    use libc::c_char;
    use std::ffi;
    use std::ptr;

    #[test]
    fn raw_opening_an_existing_file() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffclos(fptr, &mut status);
        }

        assert_eq!(status, 0);
    }

    #[test]
    fn raw_creating_a_new_file() {
        // Set up the test filename
        let tdir = tempfile::Builder::new()
            .prefix("fitsio-")
            .tempdir()
            .unwrap();
        let filename = tdir.path().join("test.fits");
        assert!(!filename.exists());

        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename.to_str().unwrap()).unwrap();

        unsafe {
            ffinit(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                &mut status,
            );
        }

        assert!(filename.exists());
    }

    #[test]
    fn getting_current_hdu_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();
        let mut hdu_num = -1;

        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 1);
    }

    #[test]
    fn changing_hdu_by_absolute_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut hdu_type = 0;
        let mut hdu_num = 0;

        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffmahd(fptr, 2, &mut hdu_type, &mut status);
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 2);
    }

    #[test]
    fn reading_header_key_value() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut long_value = 0;
        let mut float_value = 0.0;
        let mut double_value = 0.0;
        let keyname = ffi::CString::new("INTTEST").unwrap();
        let double_keyname = ffi::CString::new("DBLTEST").unwrap();
        let mut comment: Vec<c_char> = vec![0; 73];
        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffgkyj(
                fptr,
                keyname.as_ptr(),
                &mut long_value,
                ptr::null_mut(),
                &mut status,
            );
            ffgkye(
                fptr,
                keyname.as_ptr(),
                &mut float_value,
                ptr::null_mut(),
                &mut status,
            );

            // Double version is different
            ffgkyd(
                fptr,
                double_keyname.as_ptr(),
                &mut double_value,
                comment.as_mut_ptr(),
                &mut status,
            );
            ffclos(fptr, &mut status);
        }

        assert_eq!(long_value, 42);
        assert_eq!(float_value, 42.0);
        assert_eq!(double_value, 3. / 32.);

        // TODO Hacky way of getting a string out. This should be simplified.
        let comment: Vec<u8> = comment
            .iter()
            .map(|&x| x as u8)
            .filter(|&x| x != 0)
            .collect();
        let comment = String::from_utf8(comment).unwrap();
        assert_eq!(comment, "Double value");
    }

    // #[test]
    // fn api_usage() {
    // use fitsio::FitsFile;
    //
    // let mut f = FitsFile::open("../testdata/full_example.fits");
    // let mut primary_hdu = f.primary_hdu();
    // let header = primary_hdu.header();
    // let exposure_time: f32 = header["exposure"];
    // }
    //
}
<commit_msg>Fix clippy warning on nightly<commit_after>//! This package was automatically generated with [`rust-bindgen`][1] and as such was not
//! user-generated.
//!
//! The functions contained are expected to be used with [`fitsio`][2], a high level API wrapper
//! around the low level direct C-bindings, though the bindings are complete enough to be usable.
//!
//! This code will not be directly documented, and so users should refer to the [`fitsio` C
//! documentation][3] for usage.
//!
//! ## Note about function names
//!
//! Unfortunately we must use fits short names throughout. The C-api exposes long names for
//! functions which are more descriptive, for example `fits_open_file` instead of `ffopen`, but the
//! symbols available in the library have only short names, and the long names are merely
//! preprocessor definitions.
//!
//! ## Examples
//!
//! ```rust
//! use std::ptr;
//! use std::ffi;
//! # use fitsio_sys_bindgen as fitsio_sys;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let filename = ffi::CString::new("!/tmp/test.fits").unwrap();
//! let mut fptr = ptr::null_mut();
//! let mut status = 0;
//!
//! unsafe {
//!     // Create a new file, clobbering any pre-existing file
//!     fitsio_sys::ffinit(&mut fptr as *mut *mut _,
//!         filename.as_ptr(),
//!         &mut status);
//!
//!     // Add an empty primary HDU
//!     fitsio_sys::ffphps(fptr, 8, 0, ptr::null_mut(), &mut status);
//!
//!     // Finally close the file
//!     fitsio_sys::ffclos(fptr, &mut status);
//! }
//!
//! assert_eq!(status, 0);
//! # Ok(())
//! # }
//! ```
//!
//! [1]: https://github.com/servo/rust-bindgen
//! [2]: https://crates.io/crates/fitsio
//! [3]: http://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/cfitsio.html

#![allow(
    non_upper_case_globals,
    non_camel_case_types,
    non_snake_case,
    improper_ctypes
)]
// Prevent clippy from throwing errors in generated code
#![allow(
    clippy::upper_case_acronyms,
    clippy::unreadable_literal,
    clippy::transmute_ptr_to_ptr,
    clippy::redundant_static_lifetimes,
    clippy::missing_safety_doc,
    clippy::useless_transmute,
    clippy::trivially_copy_pass_by_ref,
    clippy::too_many_arguments,
    clippy::should_implement_trait
)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(test)]
mod test {
    use super::*;
    use libc::c_char;
    use std::ffi;
    use std::ptr;

    #[test]
    fn raw_opening_an_existing_file() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffclos(fptr, &mut status);
        }

        assert_eq!(status, 0);
    }

    #[test]
    fn raw_creating_a_new_file() {
        // Set up the test filename
        let tdir = tempfile::Builder::new()
            .prefix("fitsio-")
            .tempdir()
            .unwrap();
        let filename = tdir.path().join("test.fits");
        assert!(!filename.exists());

        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename.to_str().unwrap()).unwrap();

        unsafe {
            ffinit(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                &mut status,
            );
        }

        assert!(filename.exists());
    }

    #[test]
    fn getting_current_hdu_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();
        let mut hdu_num = -1;

        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 1);
    }

    #[test]
    fn changing_hdu_by_absolute_number() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut hdu_type = 0;
        let mut hdu_num = 0;

        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffmahd(fptr, 2, &mut hdu_type, &mut status);
            ffghdn(fptr, &mut hdu_num);
            ffclos(fptr, &mut status);
        }

        assert_eq!(hdu_num, 2);
    }

    #[test]
    fn reading_header_key_value() {
        let mut fptr = ptr::null_mut();
        let mut status = -1;
        let c_filename = ffi::CString::new("../testdata/full_example.fits").unwrap();

        let mut long_value = 0;
        let mut float_value = 0.0;
        let mut double_value = 0.0;
        let keyname = ffi::CString::new("INTTEST").unwrap();
        let double_keyname = ffi::CString::new("DBLTEST").unwrap();
        let mut comment: Vec<c_char> = vec![0; 73];
        unsafe {
            ffopen(
                &mut fptr as *mut *mut fitsfile,
                c_filename.as_ptr(),
                0,
                &mut status,
            );
            ffgkyj(
                fptr,
                keyname.as_ptr(),
                &mut long_value,
                ptr::null_mut(),
                &mut status,
            );
            ffgkye(
                fptr,
                keyname.as_ptr(),
                &mut float_value,
                ptr::null_mut(),
                &mut status,
            );

            // Double version is different
            ffgkyd(
                fptr,
                double_keyname.as_ptr(),
                &mut double_value,
                comment.as_mut_ptr(),
                &mut status,
            );
            ffclos(fptr, &mut status);
        }

        assert_eq!(long_value, 42);
        assert_eq!(float_value, 42.0);
        assert_eq!(double_value, 3. / 32.);

        // TODO Hacky way of getting a string out. This should be simplified.
        let comment: Vec<u8> = comment
            .iter()
            .map(|&x| x as u8)
            .filter(|&x| x != 0)
            .collect();
        let comment = String::from_utf8(comment).unwrap();
        assert_eq!(comment, "Double value");
    }

    // #[test]
    // fn api_usage() {
    // use fitsio::FitsFile;
    //
    // let mut f = FitsFile::open("../testdata/full_example.fits");
    // let mut primary_hdu = f.primary_hdu();
    // let header = primary_hdu.header();
    // let exposure_time: f32 = header["exposure"];
    // }
    //
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter, Write};
use std::str;

pub struct MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    value: DisplayValue<T>,
    escaper: E,
}

impl<E, T> MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    pub fn new_unsafe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Unsafe(value),
            escaper,
        }
    }

    pub fn new_safe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Safe(value),
            escaper,
        }
    }

    pub fn mark_safe(mut self) -> MarkupDisplay<E, T> {
        self.value = match self.value {
            DisplayValue::Unsafe(t) => DisplayValue::Safe(t),
            _ => self.value,
        };
        self
    }
}

impl<E, T> Display for MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match self.value {
            DisplayValue::Unsafe(ref t) => write!(
                EscapeWriter {
                    fmt,
                    escaper: &self.escaper
                },
                "{}",
                t
            ),
            DisplayValue::Safe(ref t) => t.fmt(fmt),
        }
    }
}

pub struct EscapeWriter<'a, E, W> {
    fmt: W,
    escaper: &'a E,
}

impl<'a, E, W> Write for EscapeWriter<'a, E, W>
where
    W: Write,
    E: Escaper,
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.escaper.write_escaped(&mut self.fmt, s)
    }
}

pub fn escape<E>(string: &str, escaper: E) -> Escaped<'_, E>
where
    E: Escaper,
{
    Escaped { string, escaper }
}

pub struct Escaped<'a, E>
where
    E: Escaper,
{
    string: &'a str,
    escaper: E,
}

impl<'a, E> ::std::fmt::Display for Escaped<'a, E>
where
    E: Escaper,
{
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.escaper.write_escaped(fmt, self.string)
    }
}

pub struct Html;

macro_rules! escaping_body {
    ($start:ident, $i:ident, $fmt:ident, $bytes:ident, $quote:expr) => {{
        if $start < $i {
            $fmt.write_str(unsafe { str::from_utf8_unchecked(&$bytes[$start..$i]) })?;
        }
        $fmt.write_str($quote)?;
        $start = $i + 1;
    }};
}

impl Escaper for Html {
    fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
    where
        W: Write,
    {
        let bytes = string.as_bytes();
        let mut start = 0;
        for (i, b) in bytes.iter().enumerate() {
            if b.wrapping_sub(b'"') <= FLAG {
                match *b {
                    b'<' => escaping_body!(start, i, fmt, bytes, "<"),
                    b'>' => escaping_body!(start, i, fmt, bytes, ">"),
                    b'&' => escaping_body!(start, i, fmt, bytes, "&"),
                    b'"' => escaping_body!(start, i, fmt, bytes, """),
                    b'\'' => escaping_body!(start, i, fmt, bytes, "'"),
                    b'/' => escaping_body!(start, i, fmt, bytes, "/"),
                    _ => (),
                }
            }
        }
        fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) })
    }
}

pub struct Text;

impl Escaper for Text {
    fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
    where
        W: Write,
    {
        fmt.write_str(string)
    }
}

#[derive(Debug, PartialEq)]
enum DisplayValue<T>
where
    T: Display,
{
    Safe(T),
    Unsafe(T),
}

pub trait Escaper {
    fn write_escaped<W>(&self, fmt: W, string: &str) -> fmt::Result
    where
        W: Write;
}

const FLAG: u8 = b'>' - b'"';

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_escape() {
        assert_eq!(escape("", Html).to_string(), "");
        assert_eq!(escape("<&>", Html).to_string(), "<&>");
        assert_eq!(escape("bla&", Html).to_string(), "bla&");
        assert_eq!(escape("<foo", Html).to_string(), "<foo");
        assert_eq!(escape("bla&h", Html).to_string(), "bla&h");
    }
}
<commit_msg>Update `EscapeWriter` HTML implementation to not output empty strings<commit_after>use std::fmt::{self, Display, Formatter, Write};
use std::str;

pub struct MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    value: DisplayValue<T>,
    escaper: E,
}

impl<E, T> MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    pub fn new_unsafe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Unsafe(value),
            escaper,
        }
    }

    pub fn new_safe(value: T, escaper: E) -> Self {
        Self {
            value: DisplayValue::Safe(value),
            escaper,
        }
    }

    pub fn mark_safe(mut self) -> MarkupDisplay<E, T> {
        self.value = match self.value {
            DisplayValue::Unsafe(t) => DisplayValue::Safe(t),
            _ => self.value,
        };
        self
    }
}

impl<E, T> Display for MarkupDisplay<E, T>
where
    E: Escaper,
    T: Display,
{
    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
        match self.value {
            DisplayValue::Unsafe(ref t) => write!(
                EscapeWriter {
                    fmt,
                    escaper: &self.escaper
                },
                "{}",
                t
            ),
            DisplayValue::Safe(ref t) => t.fmt(fmt),
        }
    }
}

pub struct EscapeWriter<'a, E, W> {
    fmt: W,
    escaper: &'a E,
}

impl<'a, E, W> Write for EscapeWriter<'a, E, W>
where
    W: Write,
    E: Escaper,
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.escaper.write_escaped(&mut self.fmt, s)
    }
}

pub fn escape<E>(string: &str, escaper: E) -> Escaped<'_, E>
where
    E: Escaper,
{
    Escaped { string, escaper }
}

pub struct Escaped<'a, E>
where
    E: Escaper,
{
    string: &'a str,
    escaper: E,
}

impl<'a, E> ::std::fmt::Display for Escaped<'a, E>
where
    E: Escaper,
{
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.escaper.write_escaped(fmt, self.string)
    }
}

pub struct Html;

macro_rules! escaping_body {
    ($start:ident, $i:ident, $fmt:ident, $bytes:ident, $quote:expr) => {{
        if $start < $i {
            $fmt.write_str(unsafe { str::from_utf8_unchecked(&$bytes[$start..$i]) })?;
        }
        $fmt.write_str($quote)?;
        $start = $i + 1;
    }};
}

impl Escaper for Html {
    fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
    where
        W: Write,
    {
        let bytes = string.as_bytes();
        let mut start = 0;
        for (i, b) in bytes.iter().enumerate() {
            if b.wrapping_sub(b'"') <= FLAG {
                match *b {
                    b'<' => escaping_body!(start, i, fmt, bytes, "<"),
                    b'>' => escaping_body!(start, i, fmt, bytes, ">"),
                    b'&' => escaping_body!(start, i, fmt, bytes, "&"),
                    b'"' => escaping_body!(start, i, fmt, bytes, """),
                    b'\'' => escaping_body!(start, i, fmt, bytes, "'"),
                    b'/' => escaping_body!(start, i, fmt, bytes, "/"),
                    _ => (),
                }
            }
        }
        if start < bytes.len() {
            fmt.write_str(unsafe { str::from_utf8_unchecked(&bytes[start..]) })
        } else {
            Ok(())
        }
    }
}

pub struct Text;

impl Escaper for Text {
    fn write_escaped<W>(&self, mut fmt: W, string: &str) -> fmt::Result
    where
        W: Write,
    {
        fmt.write_str(string)
    }
}

#[derive(Debug, PartialEq)]
enum DisplayValue<T>
where
    T: Display,
{
    Safe(T),
    Unsafe(T),
}

pub trait Escaper {
    fn write_escaped<W>(&self, fmt: W, string: &str) -> fmt::Result
    where
        W: Write;
}

const FLAG: u8 = b'>' - b'"';

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_escape() {
        assert_eq!(escape("", Html).to_string(), "");
        assert_eq!(escape("<&>", Html).to_string(), "<&>");
        assert_eq!(escape("bla&", Html).to_string(), "bla&");
        assert_eq!(escape("<foo", Html).to_string(), "<foo");
        assert_eq!(escape("bla&h", Html).to_string(), "bla&h");
    }
}
<|endoftext|>


<commit_before>// pub struct Peer {
//     client_id: String,
//     capabilities: Vec<Capability>,
//     address: SocketAddr,

//     id: H512,
//     remote_id: H512,

//     socket: TcpStream,
// }
<commit_msg>rlpx: implement Peer::connect_client using futures<commit_after>use errors::ECIESError;
use ecies::{ECIESCodec, ECIESValue};
use futures::future;
use futures::{Future, Stream, Sink};
use tokio_core::net::TcpStream;
use tokio_core::reactor::Handle;
use tokio_io::AsyncRead;
use tokio_io::codec::Framed;
use secp256k1::key::SecretKey;
use bigint::H512;
use std::net::SocketAddr;
use std::io;

pub struct Peer {
    stream: Framed<TcpStream, ECIESCodec>,
    remote_id: H512,
}

impl Peer {
    pub fn connect_client(
        addr: &SocketAddr, handle: &Handle,
        secret_key: SecretKey, remote_id: H512
    ) -> Box<Future<Item = Peer, Error = io::Error>> {
        let ecies = match ECIESCodec::new_client(secret_key, remote_id) {
            Ok(val) => val,
            Err(e) => return Box::new(future::err(
                io::Error::new(io::ErrorKind::Other, "invalid handshake")))
                as Box<Future<Item = Peer, Error = io::Error>>,
        };

        let stream = TcpStream::connect(addr, handle)
            .and_then(|socket| socket.framed(ecies).send(ECIESValue::Auth))
            .and_then(|transport| transport.into_future().map_err(|(e, _)| e))
            .and_then(move |(ack, transport)| {
                if ack == Some(ECIESValue::Ack) {
                    Ok(Peer {
                        stream: transport,
                        remote_id: remote_id,
                    })
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "invalid handshake"))
                }
            });

        Box::new(stream)
    }
}
<|endoftext|>


<commit_before><commit_msg>re-enable start_incoming support<commit_after><|endoftext|>


<commit_before><commit_msg>function to check movement bounds on the ship<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2021 Guillaume Desmottes <guillaume@desmottes.be>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at
// <https://mozilla.org/MPL/2.0/>.
//
// SPDX-License-Identifier: MPL-2.0

use gst::glib;

mod spotifyaudiosrc;

fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    spotifyaudiosrc::register(plugin)?;
    Ok(())
}

gst::plugin_define!(
    spotify,
    env!("CARGO_PKG_DESCRIPTION"),
    plugin_init,
    concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")),
    "MIT/X11",
    env!("CARGO_PKG_NAME"),
    env!("CARGO_PKG_NAME"),
    env!("CARGO_PKG_REPOSITORY"),
    env!("BUILD_REL_DATE")
);
<commit_msg>spotify: fix license when registering plugin<commit_after>// Copyright (C) 2021 Guillaume Desmottes <guillaume@desmottes.be>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at
// <https://mozilla.org/MPL/2.0/>.
//
// SPDX-License-Identifier: MPL-2.0

use gst::glib;

mod spotifyaudiosrc;

fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
    spotifyaudiosrc::register(plugin)?;
    Ok(())
}

gst::plugin_define!(
    spotify,
    env!("CARGO_PKG_DESCRIPTION"),
    plugin_init,
    concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")),
    // FIXME: MPL-2.0 is only allowed since 1.18.3 (as unknown) and 1.20 (as known)
    "MPL",
    env!("CARGO_PKG_NAME"),
    env!("CARGO_PKG_NAME"),
    env!("CARGO_PKG_REPOSITORY"),
    env!("BUILD_REL_DATE")
);
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

fn day2<R> (input: R) -> (i32, i32)
    where R: BufRead
{
    let mut part1 = 0;
    let mut part2 = 0;
    for line in input.lines() {
        let line = line.unwrap();
        let split = line.split("x");
        let mut nums = split.map(|s| s.parse().unwrap()).collect::<Vec<i32>>();
        nums.sort();
        let area1 = nums[0] * nums[1];
        let area2 = nums[0] * nums[2];
        let area3 = nums[1] * nums[2];
        part1 += area1 * 2 + area2 * 2 + area3 * 2 + area1;
        part2 += nums[0] * 2 + nums[1] * 2 + nums[0] * nums[1] * nums[2];
    }
    (part1, part2)
}

pub fn main() {
    let stdin = io::stdin();
    let (part1, part2) = day2(stdin.lock());
    println!("Part1: {}", part1);
    println!("Part2: {}", part2);
}

#[test]
fn test() {
    use std::fs::File;
    use std::io::BufReader;
    let f = File::open("../puzzles/day02/input.txt").unwrap();
    let (part1, part2) = day2(BufReader::new(f));
    assert_eq!(part1, 1598415);
    assert_eq!(part2, 3812909);
}
<commit_msg>rustfmt<commit_after>use std::io;
use std::io::prelude::*;

fn day2<R>(input: R) -> (i32, i32)
    where R: BufRead
{
    let mut part1 = 0;
    let mut part2 = 0;
    for line in input.lines() {
        let line = line.unwrap();
        let split = line.split("x");
        let mut nums = split.map(|s| s.parse().unwrap()).collect::<Vec<i32>>();
        nums.sort();
        let area1 = nums[0] * nums[1];
        let area2 = nums[0] * nums[2];
        let area3 = nums[1] * nums[2];
        part1 += area1 * 2 + area2 * 2 + area3 * 2 + area1;
        part2 += nums[0] * 2 + nums[1] * 2 + nums[0] * nums[1] * nums[2];
    }
    (part1, part2)
}

pub fn main() {
    let stdin = io::stdin();
    let (part1, part2) = day2(stdin.lock());
    println!("Part1: {}", part1);
    println!("Part2: {}", part2);
}

#[test]
fn test() {
    use std::fs::File;
    use std::io::BufReader;
    let f = File::open("../puzzles/day02/input.txt").unwrap();
    let (part1, part2) = day2(BufReader::new(f));
    assert_eq!(part1, 1598415);
    assert_eq!(part2, 3812909);
}
<|endoftext|>


<commit_before>use codec_trait::{eyre::Result, EncodeOptions};
use html_escape::{encode_double_quoted_attribute, encode_safe};
use inflector::cases::camelcase::to_camel_case;
use std::any::type_name;
use stencila_schema::*;

/// Encode a `Node` to a HTML document
pub fn encode(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
    let html = encode_address(node, options.clone());

    let EncodeOptions {
        theme, standalone, ..
    } = options.unwrap_or_default();

    let html = if standalone {
        wrap_standalone("", &theme, &html)
    } else {
        html
    };

    Ok(html)
}

/// Generate the HTML fragment for an address within a node
///
/// This function is used when translating a `Operation` (where any value of
/// the operation is a `Node` and the operation is applied to a `Node`) to a `DomOperation`
/// (where any value is either a HTML or JSON string and the operation is applied to a browser DOM).
pub fn encode_address(node: &Node, options: Option<EncodeOptions>) -> String {
    let EncodeOptions {
        bundle, compact, ..
    } = options.unwrap_or_default();

    let context = EncodeContext { root: node, bundle };
    let html = node.to_html("root", &context);

    if compact {
        html
    } else {
        indent(&html)
    }
}

/// Indent generated HTML
///
/// Originally based on https://gist.github.com/lwilli/14fb3178bd9adac3a64edfbc11f42e0d
fn indent(html: &str) -> String {
    use quick_xml::events::Event;
    use quick_xml::{Reader, Writer};

    let mut buf = Vec::new();

    let mut reader = Reader::from_str(html);
    reader.trim_text(true);

    let mut writer = Writer::new_with_indent(Vec::new(), b' ', 2);

    loop {
        let ev = reader.read_event(&mut buf);

        match ev {
            Ok(Event::Eof) => break,
            Ok(event) => writer.write_event(event),
            Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
        }
        .expect("Failed to parse XML");

        buf.clear();
    }

    std::str::from_utf8(&*writer.into_inner())
        .expect("Failed to convert a slice of bytes to a string slice")
        .to_string()
}

/// Wrap generated HTML so that it is standalone
pub fn wrap_standalone(title: &str, theme: &str, html: &str) -> String {
    let title = if title.is_empty() { "Untitled" } else { &title };
    let theme = if theme.is_empty() { "stencila" } else { &theme };

    format!(
        r#"<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{title}</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link
            href="https://unpkg.com/@stencila/thema/dist/themes/{theme}/styles.css"
            rel="stylesheet">
        <script
            src="https://unpkg.com/@stencila/components/dist/stencila-components/stencila-components.esm.js"
            type="module"></script>
        <script
            src="https://unpkg.com/@stencila/components/dist/stencila-components/stencila-components.js"
            nomodule=""></script>
        <style>
            .error {{
                font-family: mono;
                color: #9e0000;
                background: #ffd9d9;
            }}
            .todo {{
                font-family: mono;
                color: #9e9b00;
                background: #faf9de;
            }}
            .unsupported {{
                font-family: mono;
                color: #777;
                background: #eee;
            }}
        </style>
    </head>
    <body>
        {html}
    </body>
</html>"#,
        title = title,
        theme = theme,
        html = html
    )
}

/// The encoding context.
///
/// Used by child nodes to retrieve necessary information about the
/// parent nodes when rendering themselves.
pub struct EncodeContext<'a> {
    /// The root node being encoded
    root: &'a Node,

    /// Whether <img>, <audio> and <video> elements should use dataURIs
    bundle: bool,
}

impl<'a> EncodeContext<'a> {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        EncodeContext {
            root: &Node::Null(Null {}),
            bundle: false,
        }
    }
}

/// Trait for encoding a node as HTML
pub trait ToHtml {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String;
}

/// Encode a HTML element
///
/// Use this function for creating HTML strings for elements.
/// This, and other functions below, us slice `concat`, rather than `format!`
/// for performance (given that HTML generation may be done on every, or nearly every, keystroke).
fn elem(name: &str, attrs: &[String], content: &str) -> String {
    [
        "<",
        name,
        if attrs.is_empty() { "" } else { " " },
        attrs.join(" ").trim(),
        ">",
        content,
        "</",
        name,
        ">",
    ]
    .concat()
}

/// Encode an "empty" HTML element
///
/// An empty (a.k.a self-closing) element has no closing tag.
/// See https://developer.mozilla.org/en-US/docs/Glossary/Empty_element
fn elem_empty(name: &str, attrs: &[String]) -> String {
    [
        "<",
        name,
        if attrs.is_empty() { "" } else { " " },
        attrs.join(" ").trim(),
        "/>",
    ]
    .concat()
}

/// Encode a HTML element attribute, ensuring that the value is escaped correctly
fn attr(name: &str, value: &str) -> String {
    [
        name,
        "=\"",
        encode_double_quoted_attribute(&value).as_ref(),
        "\"",
    ]
    .concat()
}

/// Encode one of the attributes used to identify a property of a Stencila node
///
/// Will ensure that the name is camelCased.
fn attr_prop(name: &str) -> String {
    if name.is_empty() {
        "".to_string()
    } else if name == "root" {
        attr("data-itemscope", "root")
    } else {
        attr("data-itemprop", &to_camel_case(name))
    }
}

/// Encode the "itemtype" attribute of an HTML element
///
/// Prefer to use `attr_itemtype::<Type>` but use this when the
/// itemtype should differ from the Rust type name.
/// Note: there should always be a sibling "itemscope" attribute on the
/// element so that is added.
fn attr_itemtype_str(name: &str) -> String {
    let itemtype = match name {
        // TODO: complete list of schema.org types
        "Article" | "AudioObject" | "ImageObject" | "VideoObject" => {
            ["http://schema.org/", name].concat()
        }
        _ => ["http://schema.stenci.la/", name].concat(),
    };
    [&attr("itemtype", &itemtype), " itemscope"].concat()
}

/// Encode the "itemtype" attribute of an HTML element using the type of node
fn attr_itemtype<Type>() -> String {
    let name = type_name::<Type>();
    let name = if let Some(name) = name.strip_prefix("stencila_schema::types::") {
        name
    } else {
        tracing::error!("Unexpected type: {}", name);
        name
    };
    attr_itemtype_str(name)
}

/// Encode a "itemprop" attribute of an HTML element
///
/// Will ensure that the itemprop is camelCased.
fn attr_itemprop(itemprop: &str) -> String {
    if itemprop.is_empty() {
        "".to_string()
    } else {
        attr("itemprop", &to_camel_case(itemprop))
    }
}

/// Encode a node `id` as the "id" attribute of an HTML element
fn attr_id(id: &Option<Box<String>>) -> String {
    match id.as_deref() {
        Some(id) => attr("id", id),
        None => "".to_string(),
    }
}

/// Encode a node as JSON
///
/// Several of the below implementations use this, mainly as a placeholder,
/// until a complete implementation is finished. Ensures that the JSON is
/// properly escaped
fn json(node: &impl serde::Serialize) -> String {
    encode_safe(&serde_json::to_string_pretty(node).unwrap_or_default()).to_string()
}

/// Iterate over a slice of nodes, call a string generating function on each item
/// and concatenate the strings
pub fn concat<T, F>(slice: &[T], func: F) -> String
where
    F: FnMut(&T) -> String,
{
    slice.iter().map(func).collect::<Vec<String>>().concat()
}

mod blocks;
mod inlines;
mod nodes;
mod options;
mod primitives;
mod vecs;
#[allow(clippy::deprecated_cfg_attr)]
mod works;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::decode::decode;
    use codec_trait::eyre::bail;
    use serde_json::json;
    use test_snaps::{insta::assert_display_snapshot, snapshot_fixtures_content};
    use test_utils::{assert_json_eq, home, skip_slow_tests};

    /// Encode the HTML fragment fixtures
    #[test]
    fn encode_html_fragments() {
        snapshot_fixtures_content("fragments/html/*.html", |content| {
            let decoded = decode(content, false).expect("Unable to decode");
            let encoded = encode(
                &decoded,
                Some(EncodeOptions {
                    compact: false,
                    ..Default::default()
                }),
            )
            .unwrap();
            assert_display_snapshot!(encoded);
        });
    }

    /// Validate HTML against https://validator.github.io/validator/
    ///
    /// To run locally using the validator's Docker image:
    ///
    ///  docker run -it --rm -p 8888:8888 ghcr.io/validator/validator
    ///  RUN_SLOW_TESTS=1 HTML_VALIDATOR=http://localhost:8888 cargo test
    ///
    /// See https://github.com/validator/validator/wiki/Service-%C2%BB-Input-%C2%BB-POST-body
    /// for more on the API.
    #[tokio::test]
    async fn nu_validate() -> Result<()> {
        if skip_slow_tests() {
            return Ok(());
        }

        // Read the existing snapshot
        // We only do this for one, kitchen sink like, snapshot.
        let html =
            std::fs::read_to_string(home().join(
                "rust/codec-html/src/snapshots/encode_html_fragments@heading.html.snap",
            ))?;
        let decoded = decode(&html, false)?;
        let html = encode(
            &decoded,
            Some(EncodeOptions {
                standalone: true,
                compact: false,
                ..Default::default()
            }),
        )?;

        // Make the POST request
        let url = if let Ok(url) = std::env::var("HTML_VALIDATOR") {
            url
        } else {
            "https://validator.w3.org/nu/".to_string()
        };
        let client = reqwest::Client::new();
        let response = client
            .post([&url, "?out=json"].concat())
            .header("Content-Type", "text/html; charset=UTF-8")
            .header("Accept", "application/json")
            .header(
                "User-Agent",
                "Stencila tests (https://github.com/stencila/stencila/)",
            )
            .body(html)
            .send()
            .await?;
        let response = match response.error_for_status() {
            Ok(response) => response,
            Err(error) => bail!(error),
        };
        let json = response.text().await?;

        // Parse the result so it's easier to read any messages
        let result: serde_json::Value = serde_json::from_str(&json)?;
        assert_json_eq!(result, json!({"messages": []}));

        Ok(())
    }
}
<commit_msg>chore(HTML codec): Formatting<commit_after>use codec_trait::{eyre::Result, EncodeOptions};
use html_escape::{encode_double_quoted_attribute, encode_safe};
use inflector::cases::camelcase::to_camel_case;
use std::any::type_name;
use stencila_schema::*;

/// Encode a `Node` to a HTML document
pub fn encode(node: &Node, options: Option<EncodeOptions>) -> Result<String> {
    let html = encode_address(node, options.clone());

    let EncodeOptions {
        theme, standalone, ..
    } = options.unwrap_or_default();

    let html = if standalone {
        wrap_standalone("", &theme, &html)
    } else {
        html
    };

    Ok(html)
}

/// Generate the HTML fragment for an address within a node
///
/// This function is used when translating a `Operation` (where any value of
/// the operation is a `Node` and the operation is applied to a `Node`) to a `DomOperation`
/// (where any value is either a HTML or JSON string and the operation is applied to a browser DOM).
pub fn encode_address(node: &Node, options: Option<EncodeOptions>) -> String {
    let EncodeOptions {
        bundle, compact, ..
    } = options.unwrap_or_default();

    let context = EncodeContext { root: node, bundle };
    let html = node.to_html("root", &context);

    if compact {
        html
    } else {
        indent(&html)
    }
}

/// Indent generated HTML
///
/// Originally based on https://gist.github.com/lwilli/14fb3178bd9adac3a64edfbc11f42e0d
fn indent(html: &str) -> String {
    use quick_xml::events::Event;
    use quick_xml::{Reader, Writer};

    let mut buf = Vec::new();

    let mut reader = Reader::from_str(html);
    reader.trim_text(true);

    let mut writer = Writer::new_with_indent(Vec::new(), b' ', 2);

    loop {
        let ev = reader.read_event(&mut buf);

        match ev {
            Ok(Event::Eof) => break,
            Ok(event) => writer.write_event(event),
            Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
        }
        .expect("Failed to parse XML");

        buf.clear();
    }

    std::str::from_utf8(&*writer.into_inner())
        .expect("Failed to convert a slice of bytes to a string slice")
        .to_string()
}

/// Wrap generated HTML so that it is standalone
pub fn wrap_standalone(title: &str, theme: &str, html: &str) -> String {
    let title = if title.is_empty() { "Untitled" } else { &title };
    let theme = if theme.is_empty() { "stencila" } else { &theme };

    format!(
        r#"<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{title}</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link
            href="https://unpkg.com/@stencila/thema/dist/themes/{theme}/styles.css"
            rel="stylesheet">
        <script
            src="https://unpkg.com/@stencila/components/dist/stencila-components/stencila-components.esm.js"
            type="module"></script>
        <script
            src="https://unpkg.com/@stencila/components/dist/stencila-components/stencila-components.js"
            nomodule=""></script>
        <style>
            .error {{
                font-family: mono;
                color: #9e0000;
                background: #ffd9d9;
            }}
            .todo {{
                font-family: mono;
                color: #9e9b00;
                background: #faf9de;
            }}
            .unsupported {{
                font-family: mono;
                color: #777;
                background: #eee;
            }}
        </style>
    </head>
    <body>
        {html}
    </body>
</html>"#,
        title = title,
        theme = theme,
        html = html
    )
}

/// The encoding context.
///
/// Used by child nodes to retrieve necessary information about the
/// parent nodes when rendering themselves.
pub struct EncodeContext<'a> {
    /// The root node being encoded
    root: &'a Node,

    /// Whether <img>, <audio> and <video> elements should use dataURIs
    bundle: bool,
}

impl<'a> EncodeContext<'a> {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        EncodeContext {
            root: &Node::Null(Null {}),
            bundle: false,
        }
    }
}

/// Trait for encoding a node as HTML
pub trait ToHtml {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String;
}

/// Encode a HTML element
///
/// Use this function for creating HTML strings for elements.
/// This, and other functions below, us slice `concat`, rather than `format!`
/// for performance (given that HTML generation may be done on every, or nearly every, keystroke).
fn elem(name: &str, attrs: &[String], content: &str) -> String {
    [
        "<",
        name,
        if attrs.is_empty() { "" } else { " " },
        attrs.join(" ").trim(),
        ">",
        content,
        "</",
        name,
        ">",
    ]
    .concat()
}

/// Encode an "empty" HTML element
///
/// An empty (a.k.a self-closing) element has no closing tag.
/// See https://developer.mozilla.org/en-US/docs/Glossary/Empty_element
fn elem_empty(name: &str, attrs: &[String]) -> String {
    [
        "<",
        name,
        if attrs.is_empty() { "" } else { " " },
        attrs.join(" ").trim(),
        "/>",
    ]
    .concat()
}

/// Encode a HTML element attribute, ensuring that the value is escaped correctly
fn attr(name: &str, value: &str) -> String {
    [
        name,
        "=\"",
        encode_double_quoted_attribute(&value).as_ref(),
        "\"",
    ]
    .concat()
}

/// Encode one of the attributes used to identify a property of a Stencila node
///
/// Will ensure that the name is camelCased.
fn attr_prop(name: &str) -> String {
    if name.is_empty() {
        "".to_string()
    } else if name == "root" {
        attr("data-itemscope", "root")
    } else {
        attr("data-itemprop", &to_camel_case(name))
    }
}

/// Encode the "itemtype" attribute of an HTML element
///
/// Prefer to use `attr_itemtype::<Type>` but use this when the
/// itemtype should differ from the Rust type name.
/// Note: there should always be a sibling "itemscope" attribute on the
/// element so that is added.
fn attr_itemtype_str(name: &str) -> String {
    let itemtype = match name {
        // TODO: complete list of schema.org types
        "Article" | "AudioObject" | "ImageObject" | "VideoObject" => {
            ["http://schema.org/", name].concat()
        }
        _ => ["http://schema.stenci.la/", name].concat(),
    };
    [&attr("itemtype", &itemtype), " itemscope"].concat()
}

/// Encode the "itemtype" attribute of an HTML element using the type of node
fn attr_itemtype<Type>() -> String {
    let name = type_name::<Type>();
    let name = if let Some(name) = name.strip_prefix("stencila_schema::types::") {
        name
    } else {
        tracing::error!("Unexpected type: {}", name);
        name
    };
    attr_itemtype_str(name)
}

/// Encode a "itemprop" attribute of an HTML element
///
/// Will ensure that the itemprop is camelCased.
fn attr_itemprop(itemprop: &str) -> String {
    if itemprop.is_empty() {
        "".to_string()
    } else {
        attr("itemprop", &to_camel_case(itemprop))
    }
}

/// Encode a node `id` as the "id" attribute of an HTML element
fn attr_id(id: &Option<Box<String>>) -> String {
    match id.as_deref() {
        Some(id) => attr("id", id),
        None => "".to_string(),
    }
}

/// Encode a node as JSON
///
/// Several of the below implementations use this, mainly as a placeholder,
/// until a complete implementation is finished. Ensures that the JSON is
/// properly escaped
fn json(node: &impl serde::Serialize) -> String {
    encode_safe(&serde_json::to_string_pretty(node).unwrap_or_default()).to_string()
}

/// Iterate over a slice of nodes, call a string generating function on each item
/// and concatenate the strings
pub fn concat<T, F>(slice: &[T], func: F) -> String
where
    F: FnMut(&T) -> String,
{
    slice.iter().map(func).collect::<Vec<String>>().concat()
}

mod blocks;
mod inlines;
mod nodes;
mod options;
mod primitives;
mod vecs;
#[allow(clippy::deprecated_cfg_attr)]
mod works;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::decode::decode;
    use codec_trait::eyre::bail;
    use serde_json::json;
    use test_snaps::{insta::assert_display_snapshot, snapshot_fixtures_content};
    use test_utils::{assert_json_eq, home, skip_slow_tests};

    /// Encode the HTML fragment fixtures
    #[test]
    fn encode_html_fragments() {
        snapshot_fixtures_content("fragments/html/*.html", |content| {
            let decoded = decode(content, false).expect("Unable to decode");
            let encoded = encode(
                &decoded,
                Some(EncodeOptions {
                    compact: false,
                    ..Default::default()
                }),
            )
            .unwrap();
            assert_display_snapshot!(encoded);
        });
    }

    /// Validate HTML against https://validator.github.io/validator/
    ///
    /// To run locally using the validator's Docker image:
    ///
    ///  docker run -it --rm -p 8888:8888 ghcr.io/validator/validator
    ///  RUN_SLOW_TESTS=1 HTML_VALIDATOR=http://localhost:8888 cargo test
    ///
    /// See https://github.com/validator/validator/wiki/Service-%C2%BB-Input-%C2%BB-POST-body
    /// for more on the API.
    #[tokio::test]
    async fn nu_validate() -> Result<()> {
        if skip_slow_tests() {
            return Ok(());
        }

        // Read the existing snapshot
        // We only do this for one, kitchen sink like, snapshot.
        let html = std::fs::read_to_string(
            home().join("rust/codec-html/src/snapshots/encode_html_fragments@heading.html.snap"),
        )?;
        let decoded = decode(&html, false)?;
        let html = encode(
            &decoded,
            Some(EncodeOptions {
                standalone: true,
                compact: false,
                ..Default::default()
            }),
        )?;

        // Make the POST request
        let url = if let Ok(url) = std::env::var("HTML_VALIDATOR") {
            url
        } else {
            "https://validator.w3.org/nu/".to_string()
        };
        let client = reqwest::Client::new();
        let response = client
            .post([&url, "?out=json"].concat())
            .header("Content-Type", "text/html; charset=UTF-8")
            .header("Accept", "application/json")
            .header(
                "User-Agent",
                "Stencila tests (https://github.com/stencila/stencila/)",
            )
            .body(html)
            .send()
            .await?;
        let response = match response.error_for_status() {
            Ok(response) => response,
            Err(error) => bail!(error),
        };
        let json = response.text().await?;

        // Parse the result so it's easier to read any messages
        let result: serde_json::Value = serde_json::from_str(&json)?;
        assert_json_eq!(result, json!({"messages": []}));

        Ok(())
    }
}
<|endoftext|>


<commit_before>use rustc_errors::Applicability;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::DefIdTree;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;

use crate::utils;
use if_chain::if_chain;

declare_clippy_lint! {
    /// **What it does:**
    /// Suggests alternatives for useless applications of `?` in terminating expressions
    ///
    /// **Why is this bad?** There's no reason to use ? to short-circuit when execution of the body will end there anyway.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// struct TO {
    ///     magic: Option<usize>,
    /// }
    ///
    /// fn f(to: TO) -> Option<usize> {
    ///     Some(to.magic?)
    /// }
    ///
    /// struct TR {
    ///     magic: Result<usize, bool>,
    /// }
    ///
    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
    ///     tr.and_then(|t| Ok(t.magic?))
    /// }
    ///
    /// ```
    /// Use instead:
    /// ```rust
    /// struct TO {
    ///     magic: Option<usize>,
    /// }
    ///
    /// fn f(to: TO) -> Option<usize> {
    ///    to.magic
    /// }
    ///
    /// struct TR {
    ///     magic: Result<usize, bool>,
    /// }
    ///
    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
    ///     tr.and_then(|t| t.magic)
    /// }
    /// ```
    pub NEEDLESS_QUESTION_MARK,
    complexity,
    "Suggest value.inner_option instead of Some(value.inner_option?). The same goes for Result<T, E>."
}

const NEEDLESS_QUESTION_MARK_RESULT_MSRV: RustcVersion = RustcVersion::new(1, 13, 0);
const NEEDLESS_QUESTION_MARK_OPTION_MSRV: RustcVersion = RustcVersion::new(1, 22, 0);

pub struct NeedlessQuestionMark {
    msrv: Option<RustcVersion>,
}

impl NeedlessQuestionMark {
    #[must_use]
    pub fn new(msrv: Option<RustcVersion>) -> Self {
        Self { msrv }
    }
}

impl_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);

#[derive(Debug)]
enum SomeOkCall<'a> {
    SomeCall(&'a Expr<'a>, &'a Expr<'a>),
    OkCall(&'a Expr<'a>, &'a Expr<'a>),
}

impl LateLintPass<'_> for NeedlessQuestionMark {
    /*
     * The question mark operator is compatible with both Result<T, E> and Option<T>,
     * from Rust 1.13 and 1.22 respectively.
     */

    /*
     * What do we match:
     * Expressions that look like this:
     * Some(option?), Ok(result?)
     *
     * Where do we match:
     *      Last expression of a body
     *      Return statement
     *      A body's value (single line closure)
     *
     * What do we not match:
     *      Implicit calls to `from(..)` on the error value
     */

    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
        let e = match &expr.kind {
            ExprKind::Ret(Some(e)) => e,
            _ => return,
        };

        if let Some(ok_some_call) = is_some_or_ok_call(self, cx, e) {
            emit_lint(cx, &ok_some_call);
        }
    }

    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
        // Function / Closure block
        let expr_opt = if let ExprKind::Block(block, _) = &body.value.kind {
            block.expr
        } else {
            // Single line closure
            Some(&body.value)
        };

        if_chain! {
            if let Some(expr) = expr_opt;
            if let Some(ok_some_call) = is_some_or_ok_call(self, cx, expr);
            then {
                emit_lint(cx, &ok_some_call);
            }
        };
    }

    extract_msrv_attr!(LateContext);
}

fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) {
    let (entire_expr, inner_expr) = match expr {
        SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner),
    };

    utils::span_lint_and_sugg(
        cx,
        NEEDLESS_QUESTION_MARK,
        entire_expr.span,
        "Question mark operator is useless here",
        "try",
        format!("{}", utils::snippet(cx, inner_expr.span, r#""...""#)),
        Applicability::MachineApplicable,
    );
}

fn is_some_or_ok_call<'a>(
    nqml: &NeedlessQuestionMark,
    cx: &'a LateContext<'_>,
    expr: &'a Expr<'_>,
) -> Option<SomeOkCall<'a>> {
    if_chain! {
        // Check outer expression matches CALL_IDENT(ARGUMENT) format
        if let ExprKind::Call(path, args) = &expr.kind;
        if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind;
        if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res);

        // Extract inner expression from ARGUMENT
        if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind;
        if let ExprKind::Call(called, args) = &inner_expr_with_q.kind;
        if args.len() == 1;

        if let ExprKind::Path(QPath::LangItem(LangItem::TryIntoResult, _)) = &called.kind;
        then {
            // Extract inner expr type from match argument generated by
            // question mark operator
            let inner_expr = &args[0];

            let inner_ty = cx.typeck_results().expr_ty(inner_expr);
            let outer_ty = cx.typeck_results().expr_ty(expr);

            // Check if outer and inner type are Option
            let outer_is_some = utils::is_type_diagnostic_item(cx, outer_ty, sym::option_type);
            let inner_is_some = utils::is_type_diagnostic_item(cx, inner_ty, sym::option_type);

            // Check for Option MSRV
            let meets_option_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV);
            if outer_is_some && inner_is_some && meets_option_msrv {
                return Some(SomeOkCall::SomeCall(expr, inner_expr));
            }

            // Check if outer and inner type are Result
            let outer_is_result = utils::is_type_diagnostic_item(cx, outer_ty, sym::result_type);
            let inner_is_result = utils::is_type_diagnostic_item(cx, inner_ty, sym::result_type);

            // Additional check: if the error type of the Result can be converted
            // via the From trait, then don't match
            let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr);

            // Must meet Result MSRV
            let meets_result_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV);
            if outer_is_result && inner_is_result && does_not_call_from && meets_result_msrv {
                return Some(SomeOkCall::OkCall(expr, inner_expr));
            }
        }
    }

    None
}

fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool {
    return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr);
}

fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool {
    if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() {
        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
            if let Some(variant_id) = cx.tcx.parent(id) {
                return variant_id == ok_id;
            }
        }
    }
    false
}

fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool {
    if let Some(some_id) = cx.tcx.lang_items().option_some_variant() {
        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
            if let Some(variant_id) = cx.tcx.parent(id) {
                return variant_id == some_id;
            }
        }
    }
    false
}
<commit_msg>Auto merge of #6565 - giraffate:small_fixes_of_doc_in_needless_question_mark, r=phansch<commit_after>use rustc_errors::Applicability;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::DefIdTree;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;

use crate::utils;
use if_chain::if_chain;

declare_clippy_lint! {
    /// **What it does:**
    /// Suggests alternatives for useless applications of `?` in terminating expressions
    ///
    /// **Why is this bad?** There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// struct TO {
    ///     magic: Option<usize>,
    /// }
    ///
    /// fn f(to: TO) -> Option<usize> {
    ///     Some(to.magic?)
    /// }
    ///
    /// struct TR {
    ///     magic: Result<usize, bool>,
    /// }
    ///
    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
    ///     tr.and_then(|t| Ok(t.magic?))
    /// }
    ///
    /// ```
    /// Use instead:
    /// ```rust
    /// struct TO {
    ///     magic: Option<usize>,
    /// }
    ///
    /// fn f(to: TO) -> Option<usize> {
    ///    to.magic
    /// }
    ///
    /// struct TR {
    ///     magic: Result<usize, bool>,
    /// }
    ///
    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
    ///     tr.and_then(|t| t.magic)
    /// }
    /// ```
    pub NEEDLESS_QUESTION_MARK,
    complexity,
    "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
}

const NEEDLESS_QUESTION_MARK_RESULT_MSRV: RustcVersion = RustcVersion::new(1, 13, 0);
const NEEDLESS_QUESTION_MARK_OPTION_MSRV: RustcVersion = RustcVersion::new(1, 22, 0);

pub struct NeedlessQuestionMark {
    msrv: Option<RustcVersion>,
}

impl NeedlessQuestionMark {
    #[must_use]
    pub fn new(msrv: Option<RustcVersion>) -> Self {
        Self { msrv }
    }
}

impl_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);

#[derive(Debug)]
enum SomeOkCall<'a> {
    SomeCall(&'a Expr<'a>, &'a Expr<'a>),
    OkCall(&'a Expr<'a>, &'a Expr<'a>),
}

impl LateLintPass<'_> for NeedlessQuestionMark {
    /*
     * The question mark operator is compatible with both Result<T, E> and Option<T>,
     * from Rust 1.13 and 1.22 respectively.
     */

    /*
     * What do we match:
     * Expressions that look like this:
     * Some(option?), Ok(result?)
     *
     * Where do we match:
     *      Last expression of a body
     *      Return statement
     *      A body's value (single line closure)
     *
     * What do we not match:
     *      Implicit calls to `from(..)` on the error value
     */

    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
        let e = match &expr.kind {
            ExprKind::Ret(Some(e)) => e,
            _ => return,
        };

        if let Some(ok_some_call) = is_some_or_ok_call(self, cx, e) {
            emit_lint(cx, &ok_some_call);
        }
    }

    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
        // Function / Closure block
        let expr_opt = if let ExprKind::Block(block, _) = &body.value.kind {
            block.expr
        } else {
            // Single line closure
            Some(&body.value)
        };

        if_chain! {
            if let Some(expr) = expr_opt;
            if let Some(ok_some_call) = is_some_or_ok_call(self, cx, expr);
            then {
                emit_lint(cx, &ok_some_call);
            }
        };
    }

    extract_msrv_attr!(LateContext);
}

fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) {
    let (entire_expr, inner_expr) = match expr {
        SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner),
    };

    utils::span_lint_and_sugg(
        cx,
        NEEDLESS_QUESTION_MARK,
        entire_expr.span,
        "Question mark operator is useless here",
        "try",
        format!("{}", utils::snippet(cx, inner_expr.span, r#""...""#)),
        Applicability::MachineApplicable,
    );
}

fn is_some_or_ok_call<'a>(
    nqml: &NeedlessQuestionMark,
    cx: &'a LateContext<'_>,
    expr: &'a Expr<'_>,
) -> Option<SomeOkCall<'a>> {
    if_chain! {
        // Check outer expression matches CALL_IDENT(ARGUMENT) format
        if let ExprKind::Call(path, args) = &expr.kind;
        if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind;
        if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res);

        // Extract inner expression from ARGUMENT
        if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind;
        if let ExprKind::Call(called, args) = &inner_expr_with_q.kind;
        if args.len() == 1;

        if let ExprKind::Path(QPath::LangItem(LangItem::TryIntoResult, _)) = &called.kind;
        then {
            // Extract inner expr type from match argument generated by
            // question mark operator
            let inner_expr = &args[0];

            let inner_ty = cx.typeck_results().expr_ty(inner_expr);
            let outer_ty = cx.typeck_results().expr_ty(expr);

            // Check if outer and inner type are Option
            let outer_is_some = utils::is_type_diagnostic_item(cx, outer_ty, sym::option_type);
            let inner_is_some = utils::is_type_diagnostic_item(cx, inner_ty, sym::option_type);

            // Check for Option MSRV
            let meets_option_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_OPTION_MSRV);
            if outer_is_some && inner_is_some && meets_option_msrv {
                return Some(SomeOkCall::SomeCall(expr, inner_expr));
            }

            // Check if outer and inner type are Result
            let outer_is_result = utils::is_type_diagnostic_item(cx, outer_ty, sym::result_type);
            let inner_is_result = utils::is_type_diagnostic_item(cx, inner_ty, sym::result_type);

            // Additional check: if the error type of the Result can be converted
            // via the From trait, then don't match
            let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr);

            // Must meet Result MSRV
            let meets_result_msrv = utils::meets_msrv(nqml.msrv.as_ref(), &NEEDLESS_QUESTION_MARK_RESULT_MSRV);
            if outer_is_result && inner_is_result && does_not_call_from && meets_result_msrv {
                return Some(SomeOkCall::OkCall(expr, inner_expr));
            }
        }
    }

    None
}

fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool {
    return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr);
}

fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool {
    if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() {
        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
            if let Some(variant_id) = cx.tcx.parent(id) {
                return variant_id == ok_id;
            }
        }
    }
    false
}

fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool {
    if let Some(some_id) = cx.tcx.lang_items().option_some_variant() {
        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
            if let Some(variant_id) = cx.tcx.parent(id) {
                return variant_id == some_id;
            }
        }
    }
    false
}
<|endoftext|>


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

use std::env;
use std::ffi::OsString;
use std::fs as stdfs;
use std::path::PathBuf;

use crate::common::ui::UI;
use crate::hcore::crypto::CACHE_KEY_PATH_ENV_VAR;
use crate::hcore::env as henv;
use crate::hcore::fs;

use crate::config;
use crate::error::Result;

pub const ARTIFACT_PATH_ENVVAR: &'static str = "ARTIFACT_PATH";

const ORIGIN_ENVVAR: &'static str = "HAB_ORIGIN";
const STUDIO_CMD: &'static str = "hab-studio";
const STUDIO_CMD_ENVVAR: &'static str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &'static str = "core/hab-studio";

pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
    if henv::var(ORIGIN_ENVVAR).is_err() {
        let config = config::load()?;
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use std::env;
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use crate::common::ui::{UIWriter, UI};
    use crate::hcore::crypto::{default_cache_key_path, init};
    use crate::hcore::env as henv;
    use crate::hcore::fs::{am_i_root, find_command};
    use crate::hcore::os::process;
    use crate::hcore::package::PackageIdent;
    use crate::hcore::users::linux as group;

    use crate::error::{Error, Result};
    use crate::exec;
    use crate::VERSION;

    use crate::command::studio::docker;

    const SUDO_CMD: &'static str = "sudo";

    pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split("/").collect();
                    let ident = PackageIdent::from_str(&format!(
                        "{}/{}",
                        super::STUDIO_PACKAGE_IDENT,
                        version[0]
                    ))?;
                    exec::command_from_min_pkg(
                        ui,
                        super::STUDIO_CMD,
                        &ident,
                        &default_cache_key_path(None),
                        0,
                    )?
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                Ok(process::become_command(cmd, args)?)
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &Vec<OsString>) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == String::from("-D") {
                return true;
            }
        }

        return false;
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &Vec<OsString>) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() {
            return Ok(());
        } else if is_docker_studio(&args) {
            if has_docker_group() {
                return Ok(());
            }
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec![
                    "-p".into(),
                    "[sudo hab-studio] password for %u: ".into(),
                    "-E".into(),
                ];
                args.append(&mut env::args_os().collect());
                Ok(process::become_command(sudo_prog, args)?)
            }
            None => {
                ui.warn(format!(
                    "Could not find the `{}' command, is it in your PATH?",
                    SUDO_CMD
                ))?;
                ui.warn(
                    "Running Habitat Studio requires root or administrator privileges. \
                     Please retry this command as a super user or use a \
                     privilege-granting facility such as sudo.",
                )?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use common::ui::UI;
    use hcore::crypto::{default_cache_key_path, init};
    use hcore::env as henv;
    use hcore::fs::find_command;
    use hcore::os::process;
    use hcore::package::PackageIdent;

    use command::studio::docker;
    use error::{Error, Result};
    use exec;
    use VERSION;

    pub fn start(_ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split("/").collect();
                let ident = PackageIdent::from_str(&format!(
                    "{}/{}",
                    super::STUDIO_PACKAGE_IDENT,
                    version[0]
                ))?;
                exec::command_from_min_pkg(
                    ui,
                    super::STUDIO_CMD,
                    &ident,
                    &default_cache_key_path(None),
                    0,
                )?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &Vec<OsString>) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == String::from("-D") {
                return false;
            }
        }

        // -w/--windows is deprecated and should be removed in a post 0.64.0 release
        for arg in args.iter() {
            let str_arg = arg.to_string_lossy().to_lowercase();
            if str_arg == String::from("--windows") || str_arg == String::from("-w") {
                return true;
            }
        }

        return true;
    }
}
<commit_msg>Make rust 2018 edition fixes for non-linux<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::ffi::OsString;
use std::fs as stdfs;
use std::path::PathBuf;

use crate::common::ui::UI;
use crate::hcore::crypto::CACHE_KEY_PATH_ENV_VAR;
use crate::hcore::env as henv;
use crate::hcore::fs;

use crate::config;
use crate::error::Result;

pub const ARTIFACT_PATH_ENVVAR: &'static str = "ARTIFACT_PATH";

const ORIGIN_ENVVAR: &'static str = "HAB_ORIGIN";
const STUDIO_CMD: &'static str = "hab-studio";
const STUDIO_CMD_ENVVAR: &'static str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &'static str = "core/hab-studio";

pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
    if henv::var(ORIGIN_ENVVAR).is_err() {
        let config = config::load()?;
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use std::env;
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use crate::common::ui::{UIWriter, UI};
    use crate::hcore::crypto::{default_cache_key_path, init};
    use crate::hcore::env as henv;
    use crate::hcore::fs::{am_i_root, find_command};
    use crate::hcore::os::process;
    use crate::hcore::package::PackageIdent;
    use crate::hcore::users::linux as group;

    use crate::error::{Error, Result};
    use crate::exec;
    use crate::VERSION;

    use crate::command::studio::docker;

    const SUDO_CMD: &'static str = "sudo";

    pub fn start(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split("/").collect();
                    let ident = PackageIdent::from_str(&format!(
                        "{}/{}",
                        super::STUDIO_PACKAGE_IDENT,
                        version[0]
                    ))?;
                    exec::command_from_min_pkg(
                        ui,
                        super::STUDIO_CMD,
                        &ident,
                        &default_cache_key_path(None),
                        0,
                    )?
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                Ok(process::become_command(cmd, args)?)
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &Vec<OsString>) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == String::from("-D") {
                return true;
            }
        }

        return false;
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &Vec<OsString>) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() {
            return Ok(());
        } else if is_docker_studio(&args) {
            if has_docker_group() {
                return Ok(());
            }
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec![
                    "-p".into(),
                    "[sudo hab-studio] password for %u: ".into(),
                    "-E".into(),
                ];
                args.append(&mut env::args_os().collect());
                Ok(process::become_command(sudo_prog, args)?)
            }
            None => {
                ui.warn(format!(
                    "Could not find the `{}' command, is it in your PATH?",
                    SUDO_CMD
                ))?;
                ui.warn(
                    "Running Habitat Studio requires root or administrator privileges. \
                     Please retry this command as a super user or use a \
                     privilege-granting facility such as sudo.",
                )?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use std::ffi::OsString;
    use std::path::PathBuf;
    use std::str::FromStr;

    use common::ui::UI;
    use hcore::crypto::{default_cache_key_path, init};
    use hcore::env as henv;
    use hcore::fs::find_command;
    use hcore::os::process;
    use hcore::package::PackageIdent;

    use crate::command::studio::docker;
    use crate::error::{Error, Result};
    use crate::exec;
    use crate::VERSION;

    pub fn start(_ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: Vec<OsString>) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split("/").collect();
                let ident = PackageIdent::from_str(&format!(
                    "{}/{}",
                    super::STUDIO_PACKAGE_IDENT,
                    version[0]
                ))?;
                exec::command_from_min_pkg(
                    ui,
                    super::STUDIO_CMD,
                    &ident,
                    &default_cache_key_path(None),
                    0,
                )?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &Vec<OsString>) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == String::from("-D") {
                return false;
            }
        }

        // -w/--windows is deprecated and should be removed in a post 0.64.0 release
        for arg in args.iter() {
            let str_arg = arg.to_string_lossy().to_lowercase();
            if str_arg == String::from("--windows") || str_arg == String::from("-w") {
                return true;
            }
        }

        return true;
    }
}
<|endoftext|>