<commit_before>use cfg::DnfExpr;
use stdx::format_to;

use crate::{Diagnostic, DiagnosticsContext, Severity};

// Diagnostic: inactive-code
//
// This diagnostic is shown for code with inactive `#[cfg]` attributes.
pub(crate) fn inactive_code(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::InactiveCode,
) -> Option<Diagnostic> {
    // If there's inactive code somewhere in a macro, don't propagate to the call-site.
    if d.node.file_id.is_macro() {
        return None;
    }

    let inactive = DnfExpr::new(d.cfg.clone()).why_inactive(&d.opts);
    let mut message = "code is inactive due to #[cfg] directives".to_string();

    if let Some(inactive) = inactive {
        let inactive_reasons = inactive.to_string();

        if inactive_reasons.is_empty() {
            format_to!(message);
        } else {
            format_to!(message, ": {}", inactive);
        }
    }

    let res = Diagnostic::new(
        "inactive-code",
        message,
        ctx.sema.diagnostics_display_range(d.node.clone()).range,
    )
    .severity(Severity::WeakWarning)
    .with_unused(true);
    Some(res)
}

#[cfg(test)]
mod tests {
    use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig};

    pub(crate) fn check(ra_fixture: &str) {
        let config = DiagnosticsConfig::default();
        check_diagnostics_with_config(config, ra_fixture)
    }

    #[test]
    fn cfg_diagnostics() {
        check(
            r#"
fn f() {
    // The three g̶e̶n̶d̶e̶r̶s̶ statements:

    #[cfg(a)] fn f() {}  // Item statement
  //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    #[cfg(a)] {}         // Expression statement
  //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    #[cfg(a)] let x = 0; // let statement
  //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled

    abc(#[cfg(a)] 0);
      //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    let x = Struct {
        #[cfg(a)] f: 0,
      //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    };
    match () {
        () => (),
        #[cfg(a)] () => (),
      //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    }

    #[cfg(a)] 0          // Trailing expression of block
  //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
}
        "#,
        );
    }

    #[test]
    fn inactive_item() {
        // Additional tests in `cfg` crate. This only tests disabled cfgs.

        check(
            r#"
    #[cfg(no)] pub fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled

    #[cfg(no)] #[cfg(no2)] mod m;
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled

    #[cfg(all(not(a), b))] enum E {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled

    #[cfg(feature = "std")] use std;
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled

    #[cfg(any())] pub fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
"#,
        );
    }

    #[test]
    fn inactive_assoc_item() {
        // FIXME these currently don't work, hence the *
        check(
            r#"
struct Foo;
impl Foo {
    #[cfg(any())] pub fn f() {}
  //*************************** weak: code is inactive due to #[cfg] directives
}

trait Bar {
    #[cfg(any())] pub fn f() {}
  //*************************** weak: code is inactive due to #[cfg] directives
}
"#,
        );
    }

    /// Tests that `cfg` attributes behind `cfg_attr` is handled properly.
    #[test]
    fn inactive_via_cfg_attr() {
        cov_mark::check!(cfg_attr_active);
        check(
            r#"
    #[cfg_attr(not(never), cfg(no))] fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled

    #[cfg_attr(not(never), cfg(not(no)))] fn f() {}

    #[cfg_attr(never, cfg(no))] fn g() {}

    #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
"#,
        );
    }
}
<commit_msg>activate assoc item test<commit_after>use cfg::DnfExpr;
use stdx::format_to;

use crate::{Diagnostic, DiagnosticsContext, Severity};

// Diagnostic: inactive-code
//
// This diagnostic is shown for code with inactive `#[cfg]` attributes.
pub(crate) fn inactive_code(
    ctx: &DiagnosticsContext<'_>,
    d: &hir::InactiveCode,
) -> Option<Diagnostic> {
    // If there's inactive code somewhere in a macro, don't propagate to the call-site.
    if d.node.file_id.is_macro() {
        return None;
    }

    let inactive = DnfExpr::new(d.cfg.clone()).why_inactive(&d.opts);
    let mut message = "code is inactive due to #[cfg] directives".to_string();

    if let Some(inactive) = inactive {
        let inactive_reasons = inactive.to_string();

        if inactive_reasons.is_empty() {
            format_to!(message);
        } else {
            format_to!(message, ": {}", inactive);
        }
    }

    let res = Diagnostic::new(
        "inactive-code",
        message,
        ctx.sema.diagnostics_display_range(d.node.clone()).range,
    )
    .severity(Severity::WeakWarning)
    .with_unused(true);
    Some(res)
}

#[cfg(test)]
mod tests {
    use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig};

    pub(crate) fn check(ra_fixture: &str) {
        let config = DiagnosticsConfig::default();
        check_diagnostics_with_config(config, ra_fixture)
    }

    #[test]
    fn cfg_diagnostics() {
        check(
            r#"
fn f() {
    // The three g̶e̶n̶d̶e̶r̶s̶ statements:

    #[cfg(a)] fn f() {}  // Item statement
  //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    #[cfg(a)] {}         // Expression statement
  //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    #[cfg(a)] let x = 0; // let statement
  //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled

    abc(#[cfg(a)] 0);
      //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    let x = Struct {
        #[cfg(a)] f: 0,
      //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    };
    match () {
        () => (),
        #[cfg(a)] () => (),
      //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
    }

    #[cfg(a)] 0          // Trailing expression of block
  //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
}
        "#,
        );
    }

    #[test]
    fn inactive_item() {
        // Additional tests in `cfg` crate. This only tests disabled cfgs.

        check(
            r#"
    #[cfg(no)] pub fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled

    #[cfg(no)] #[cfg(no2)] mod m;
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled

    #[cfg(all(not(a), b))] enum E {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled

    #[cfg(feature = "std")] use std;
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled

    #[cfg(any())] pub fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
"#,
        );
    }

    #[test]
    fn inactive_assoc_item() {
        // FIXME these currently don't work, hence the *
        check(
            r#"
struct Foo;
impl Foo {
    #[cfg(any())] pub fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
}

trait Bar {
    #[cfg(any())] pub fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
}
"#,
        );
    }

    /// Tests that `cfg` attributes behind `cfg_attr` is handled properly.
    #[test]
    fn inactive_via_cfg_attr() {
        cov_mark::check!(cfg_attr_active);
        check(
            r#"
    #[cfg_attr(not(never), cfg(no))] fn f() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled

    #[cfg_attr(not(never), cfg(not(no)))] fn f() {}

    #[cfg_attr(never, cfg(no))] fn g() {}

    #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
"#,
        );
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;
use core::fmt;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ptr;

/// Number of words a piece of `Data` can hold.
///
/// Three words should be enough for the majority of cases. For example, you can fit inside it the
/// function pointer together with a fat pointer representing an object that needs to be destroyed.
const DATA_WORDS: usize = 3;

/// Some space to keep a `FnOnce()` object on the stack.
type Data = [usize; DATA_WORDS];

/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap.
///
/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure.
pub(crate) struct Deferred {
    call: unsafe fn(*mut u8),
    data: Data,
    _marker: PhantomData<*mut ()>, // !Send + !Sync
}

impl fmt::Debug for Deferred {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.pad("Deferred { .. }")
    }
}

impl Deferred {
    /// Constructs a new `Deferred` from a `FnOnce()`.
    pub(crate) fn new<F: FnOnce()>(f: F) -> Self {
        let size = mem::size_of::<F>();
        let align = mem::align_of::<F>();

        unsafe {
            if size <= mem::size_of::<Data>() && align <= mem::align_of::<Data>() {
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut F, f);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    let f: F = ptr::read(raw as *mut F);
                    f();
                }

                Deferred {
                    call: call::<F>,
                    data: data.assume_init(),
                    _marker: PhantomData,
                }
            } else {
                let b: Box<F> = Box::new(f);
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut Box<F>, b);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    // It's safe to cast `raw` from `*mut u8` to `*mut Box<F>`, because `raw` is
                    // originally derived from `*mut Box<F>`.
                    #[allow(clippy::cast_ptr_alignment)]
                    let b: Box<F> = ptr::read(raw as *mut Box<F>);
                    (*b)();
                }

                Deferred {
                    call: call::<F>,
                    data: data.assume_init(),
                    _marker: PhantomData,
                }
            }
        }
    }

    /// Calls the function.
    #[inline]
    pub(crate) fn call(mut self) {
        let call = self.call;
        unsafe { call(&mut self.data as *mut Data as *mut u8) };
    }
}

#[cfg(all(test, not(crossbeam_loom)))]
mod tests {
    #![allow(clippy::drop_copy)]

    use super::Deferred;
    use std::cell::Cell;

    #[test]
    fn on_stack() {
        let fired = &Cell::new(false);
        let a = [0usize; 1];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn on_heap() {
        let fired = &Cell::new(false);
        let a = [0usize; 10];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn string() {
        let a = "hello".to_string();
        let d = Deferred::new(move || assert_eq!(a, "hello"));
        d.call();
    }

    #[test]
    fn boxed_slice_i32() {
        let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice();
        let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7]));
        d.call();
    }

    #[test]
    fn long_slice_usize() {
        let a: [usize; 5] = [2, 3, 5, 7, 11];
        let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11]));
        d.call();
    }
}
<commit_msg>Don't call assume_init on Deferred's Data<commit_after>use alloc::boxed::Box;
use core::fmt;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ptr;

/// Number of words a piece of `Data` can hold.
///
/// Three words should be enough for the majority of cases. For example, you can fit inside it the
/// function pointer together with a fat pointer representing an object that needs to be destroyed.
const DATA_WORDS: usize = 3;

/// Some space to keep a `FnOnce()` object on the stack.
type Data = [usize; DATA_WORDS];

/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap.
///
/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure.
pub(crate) struct Deferred {
    call: unsafe fn(*mut u8),
    data: MaybeUninit<Data>,
    _marker: PhantomData<*mut ()>, // !Send + !Sync
}

impl fmt::Debug for Deferred {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.pad("Deferred { .. }")
    }
}

impl Deferred {
    /// Constructs a new `Deferred` from a `FnOnce()`.
    pub(crate) fn new<F: FnOnce()>(f: F) -> Self {
        let size = mem::size_of::<F>();
        let align = mem::align_of::<F>();

        unsafe {
            if size <= mem::size_of::<Data>() && align <= mem::align_of::<Data>() {
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut F, f);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    let f: F = ptr::read(raw as *mut F);
                    f();
                }

                Deferred {
                    call: call::<F>,
                    data,
                    _marker: PhantomData,
                }
            } else {
                let b: Box<F> = Box::new(f);
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut Box<F>, b);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    // It's safe to cast `raw` from `*mut u8` to `*mut Box<F>`, because `raw` is
                    // originally derived from `*mut Box<F>`.
                    #[allow(clippy::cast_ptr_alignment)]
                    let b: Box<F> = ptr::read(raw as *mut Box<F>);
                    (*b)();
                }

                Deferred {
                    call: call::<F>,
                    data,
                    _marker: PhantomData,
                }
            }
        }
    }

    /// Calls the function.
    #[inline]
    pub(crate) fn call(mut self) {
        let call = self.call;
        unsafe { call(self.data.as_mut_ptr() as *mut u8) };
    }
}

#[cfg(all(test, not(crossbeam_loom)))]
mod tests {
    #![allow(clippy::drop_copy)]

    use super::Deferred;
    use std::cell::Cell;

    #[test]
    fn on_stack() {
        let fired = &Cell::new(false);
        let a = [0usize; 1];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn on_heap() {
        let fired = &Cell::new(false);
        let a = [0usize; 10];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn string() {
        let a = "hello".to_string();
        let d = Deferred::new(move || assert_eq!(a, "hello"));
        d.call();
    }

    #[test]
    fn boxed_slice_i32() {
        let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice();
        let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7]));
        d.call();
    }

    #[test]
    fn long_slice_usize() {
        let a: [usize; 5] = [2, 3, 5, 7, 11];
        let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11]));
        d.call();
    }
}
<|endoftext|>


<commit_before>use error::Error;
use client::Client;
use params::{Metadata, Timestamp};
use resources::{Currency, Deleted};

/// The set of parameters that can be used when creating or updating a plan.
///
/// For more details see https://stripe.com/docs/api#create_plan and https://stripe.com/docs/api#update_plan.
#[derive(Default, Serialize)]
pub struct PlanParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub amount: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub currency: Option<Currency>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub interval: Option<&'a str>, // (day, week, month, year)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<&'a str>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub interval_count: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<Metadata>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub statement_descriptor: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub trial_period_days: Option<u64>,
}

/// The resource representing a Stripe plan.
///
/// For more details see https://stripe.com/docs/api#plans.
#[derive(Debug, Deserialize)]
pub struct Plan {
    pub id: String,
    pub amount: u64,
    pub created: Timestamp,
    pub currency: Currency,
    pub interval: String, // (day, week, month, year)
    pub interval_count: u64,
    pub livemode: bool,
    pub metadata: Metadata,
    pub name: String,
    pub statement_descriptor: Option<String>,
    pub trial_period_days: Option<u64>,
}

impl Plan {
    /// Creates a new plan.
    ///
    /// For more details see https://stripe.com/docs/api#create_plan.
    pub fn create(client: &Client, params: PlanParams) -> Result<Plan, Error> {
        client.post("/plans", params)
    }

    /// Retrieves the details of a plan.
    ///
    /// For more details see https://stripe.com/docs/api#retrieve_plan.
    pub fn retrieve(client: &Client, plan_id: &str) -> Result<Plan, Error> {
        client.get(&format!("/plans/{}", plan_id))
    }

    /// Updates a plan's properties.
    ///
    /// For more details see https://stripe.com/docs/api#update_plan.
    pub fn update(client: &Client, plan_id: &str, params: PlanParams) -> Result<Plan, Error> {
        client.post(&format!("/plans/{}", plan_id), params)
    }

    /// Deletes a plan.
    ///
    /// For more details see https://stripe.com/docs/api#delete_plan.
    pub fn delete(client: &Client, plan_id: &str) -> Result<Deleted, Error> {
        client.delete(&format!("/plans/{}", plan_id))
    }
}
<commit_msg>fix subscription plan member name<commit_after>use error::Error;
use client::Client;
use params::{Metadata, Timestamp};
use resources::{Currency, Deleted};

/// The set of parameters that can be used when creating or updating a plan.
///
/// For more details see https://stripe.com/docs/api#create_plan and https://stripe.com/docs/api#update_plan.
#[derive(Default, Serialize)]
pub struct PlanParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub amount: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub currency: Option<Currency>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub interval: Option<&'a str>, // (day, week, month, year)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<&'a str>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub interval_count: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<Metadata>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub statement_descriptor: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub trial_period_days: Option<u64>,
}

/// The resource representing a Stripe plan.
///
/// For more details see https://stripe.com/docs/api#plans.
#[derive(Debug, Deserialize)]
pub struct Plan {
    pub id: String,
    pub amount: u64,
    pub created: Timestamp,
    pub currency: Currency,
    pub interval: String, // (day, week, month, year)
    pub interval_count: u64,
    pub livemode: bool,
    pub metadata: Metadata,
    pub nickname: String,
    pub statement_descriptor: Option<String>,
    pub trial_period_days: Option<u64>,
}

impl Plan {
    /// Creates a new plan.
    ///
    /// For more details see https://stripe.com/docs/api#create_plan.
    pub fn create(client: &Client, params: PlanParams) -> Result<Plan, Error> {
        client.post("/plans", params)
    }

    /// Retrieves the details of a plan.
    ///
    /// For more details see https://stripe.com/docs/api#retrieve_plan.
    pub fn retrieve(client: &Client, plan_id: &str) -> Result<Plan, Error> {
        client.get(&format!("/plans/{}", plan_id))
    }

    /// Updates a plan's properties.
    ///
    /// For more details see https://stripe.com/docs/api#update_plan.
    pub fn update(client: &Client, plan_id: &str, params: PlanParams) -> Result<Plan, Error> {
        client.post(&format!("/plans/{}", plan_id), params)
    }

    /// Deletes a plan.
    ///
    /// For more details see https://stripe.com/docs/api#delete_plan.
    pub fn delete(client: &Client, plan_id: &str) -> Result<Deleted, Error> {
        client.delete(&format!("/plans/{}", plan_id))
    }
}
<|endoftext|>


<commit_before>#![cfg(windows)]

extern crate libc;
extern crate winapi;
extern crate "kernel32-sys" as kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;
use std::io::IoError;

extern "system" {
    fn CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE) -> HANDLE;
    fn ReadFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
    fn WriteFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
}

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    conin: HANDLE,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            // Unlike in Linux, we *could* use the default stdin/stdout file handles to talk
            // directly to the console. However, we need the default stdin handle for the list of
            // choices, and we need to write just the final selection to stdout. Therefore we have
            // to explicitly create new handles to talk to the console. The gory details are
            // available at:
            //
            // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075%28v=vs.85%29.aspx
            // http://stackoverflow.com/questions/377152/what-does-createfileconin-do
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            conin: conin,
            conout: conout,
        }
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in range(0, self.height) {
            self.write(blank_line.as_slice());
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteFile(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
        let mut chars_read: DWORD = 0;
        win32!(ReadFile(self.conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));

        let mut ret = Vec::new();
        for i in range(0, chars_read) {
            ret.push(Screen::translate_byte(buf[i as usize]));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conin: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conin, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    let conout = unsafe { kernel32::GetStdHandle(-11) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<commit_msg>Check validity of console handles<commit_after>#![cfg(windows)]

extern crate libc;
extern crate winapi;
extern crate "kernel32-sys" as kernel32;

use self::kernel32::*;
use self::winapi::*;
use std::ptr;
use std::iter::repeat;
use std::cmp::min;
use screen::Key;
use screen::Key::*;
use std::io::IoError;

extern "system" {
    fn CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE) -> HANDLE;
    fn ReadFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
    fn WriteFile(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL;
}

macro_rules! win32 {
    ($funcall:expr) => (
        if unsafe { $funcall } == 0 {
            panic!("Win32 call failed");
        }
    );
}

pub struct Screen {
    pub height: u16,
    pub width: u16,
    pub visible_choices: u16,
    pub start_line: u16,
    original_console_mode: DWORD,
    original_colors: WORD,
    conin: HANDLE,
    conout: HANDLE,
}

impl Drop for Screen {
    fn drop(&mut self) {
        win32!(SetConsoleMode(self.conout, self.original_console_mode));
    }
}

impl Screen {
    pub fn open_screen() -> Screen {
        let mut orig_mode;
        let conin: HANDLE;
        let conout: HANDLE;
        unsafe {
            // Unlike in Linux, we *could* use the default stdin/stdout file handles to talk
            // directly to the console. However, we need the default stdin handle for the list of
            // choices, and we need to write just the final selection to stdout. Therefore we have
            // to explicitly create new handles to talk to the console. The gory details are
            // available at:
            //
            // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075%28v=vs.85%29.aspx
            // http://stackoverflow.com/questions/377152/what-does-createfileconin-do
            const OPEN_EXISTING: DWORD = 3;
            let rw_access = GENERIC_READ | GENERIC_WRITE;
            conin = CreateFileA("CONIN$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            conout = CreateFileA("CONOUT$\0".as_ptr() as *const i8, rw_access, FILE_SHARE_READ, ptr::null_mut(), OPEN_EXISTING, 0, ptr::null_mut());
            orig_mode = ::std::mem::uninitialized();
        }

        if conin == INVALID_HANDLE_VALUE || conout == INVALID_HANDLE_VALUE {
            panic!("Unable to open console");
        }

        let (cols, rows) = Screen::winsize(conout).unwrap();

        win32!(GetConsoleMode(conout, &mut orig_mode));
        let new_mode = orig_mode & !(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
        win32!(SetConsoleMode(conin, new_mode));

        let visible_choices = min(20, rows - 1);
        let start_line = rows - visible_choices - 1;
        let original_colors = Screen::get_original_colors(conout);
        Screen {
            height: rows,
            width: cols,
            visible_choices: visible_choices,
            start_line: start_line,
            original_console_mode: orig_mode,
            original_colors: original_colors,
            conin: conin,
            conout: conout,
        }
    }

    pub fn move_cursor(&mut self, line: u16, column: u16) {
        win32!(SetConsoleCursorPosition(self.conout, COORD { X: column as i16, Y: line as i16}));
    }

    pub fn move_cursor_to_bottom(&mut self) {
        let end_line = self.start_line + self.visible_choices;
        self.move_cursor(end_line, 0);
        self.write("\n");
    }

    pub fn blank_screen(&mut self) {
        let start_line = self.start_line;
        self.move_cursor(start_line, 0);
        let blank_line = repeat(' ').take(self.width as usize).collect::<String>();
        for _ in range(0, self.height) {
            self.write(blank_line.as_slice());
        }
        self.move_cursor(start_line, 0);
    }

    pub fn show_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: TRUE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn hide_cursor(&mut self) {
        let cursor_info = CONSOLE_CURSOR_INFO { dwSize: 100, bVisible: FALSE };
        win32!(SetConsoleCursorInfo(self.conout, &cursor_info));
    }

    pub fn write(&mut self, s: &str) {
        let mut copy = s.to_string();
        let len: DWORD = copy.len() as DWORD;
        copy.push('\0');
        let mut bytes_written: DWORD = 0;
        win32!(WriteFile(self.conout, copy.as_ptr() as PVOID, len, &mut bytes_written as LPDWORD, ptr::null_mut()));
    }

    pub fn write_inverted(&mut self, s: &str) {
        let orig = self.original_colors;
        const BLACK_ON_WHITE: WORD = (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) as WORD;
        self.set_colors(BLACK_ON_WHITE);
        self.write(s);
        self.set_colors(orig);
    }

    fn set_colors(&mut self, colors: WORD) {
        win32!(SetConsoleTextAttribute(self.conout, colors));
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    pub fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut buf: Vec<u16> = repeat(0u16).take(0x1000).collect();
        let mut chars_read: DWORD = 0;
        win32!(ReadFile(self.conin, buf.as_mut_ptr() as LPVOID, 1, &mut chars_read as LPDWORD, ptr::null_mut()));

        let mut ret = Vec::new();
        for i in range(0, chars_read) {
            ret.push(Screen::translate_byte(buf[i as usize]));
        }
        ret
    }

    fn translate_byte(byte: u16) -> Key {
        if byte == '\r' as u16 {
            Enter
        } else if byte == 127 {
            Backspace
        } else if byte & 96 == 0 {
            Control(((byte + 96u16) as u8) as char)
        } else {
            Char((byte as u8) as char)
        }
    }

    fn get_original_colors(handle: HANDLE) -> WORD {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        win32!(GetConsoleScreenBufferInfo(handle, &mut buffer_info));
        buffer_info.wAttributes
    }

    fn winsize(conin: HANDLE) -> Option<(u16, u16)> {
        let mut buffer_info = unsafe { ::std::mem::uninitialized() };
        let result = unsafe { GetConsoleScreenBufferInfo(conin, &mut buffer_info) };
        if result != 0 {
            // This code specifically computes the size of the window,
            // *not* the size of the buffer (which is easily available
            // from dwSize). I got the algorithm from:
            //
            // http://stackoverflow.com/a/12642749
            let left = buffer_info.srWindow.Left;
            let top = buffer_info.srWindow.Top;
            let right = buffer_info.srWindow.Right;
            let bottom = buffer_info.srWindow.Bottom;
            let cols = right - left + 1;
            let rows = bottom - top + 1;
            Some((cols as u16, rows as u16))
        } else {
            None
        }
    }
}

#[test]
fn winsize_test() {
    let conout = unsafe { kernel32::GetStdHandle(-11) };
    let (cols, rows) = Screen::winsize(conout).expect("Failed to get window size!");
    // We don't know the window size a priori, but we can at least
    // assert that it is within some kind of sensible range.
    assert!(cols > 40);
    assert!(rows > 40);
    assert!(cols < 1000);
    assert!(rows < 1000);
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use crate::fs::File;

impl<'a> File<'a> {

    /// For this file, return a vector of alternate file paths that, if any of
    /// them exist, mean that *this* file should be coloured as “compiled”.
    ///
    /// The point of this is to highlight compiled files such as `foo.js` when
    /// their source file `foo.coffee` exists in the same directory.
    /// For example, `foo.js` is perfectly valid without `foo.coffee`, so we
    /// don’t want to always blindly highlight `*.js` as compiled.
    /// (See also `FileExtensions#is_compiled`)
    pub fn get_source_files(&self) -> Vec<PathBuf> {
        if let Some(ext) = &self.ext {
            match &ext[..] {
                "css"   => vec![self.path.with_extension("sass"),   self.path.with_extension("less")],  // SASS, Less
                "js"    => vec![self.path.with_extension("coffee"), self.path.with_extension("ts")],  // CoffeeScript, TypeScript

                "aux" |                                          // TeX: auxiliary file
                "bbl" |                                          // BibTeX bibliography file
                "bcf" |                                          // biblatex control file
                "blg" |                                          // BibTeX log file
                "fdb_latexmk" |                                  // TeX latexmk file
                "fls" |                                          // TeX -recorder file
                "lof" |                                          // TeX list of figures
                "log" |                                          // TeX log file
                "lot" |                                          // TeX list of tables
                "toc" => vec![self.path.with_extension("tex")],  // TeX table of contents

                _ => vec![],  // No source files if none of the above
            }
        }
        else {
            vec![]  // No source files if there’s no extension, either!
        }
    }
}
<commit_msg>Recognize SCSS and Stylus as source for CSS files (#770)<commit_after>use std::path::PathBuf;

use crate::fs::File;

impl<'a> File<'a> {

    /// For this file, return a vector of alternate file paths that, if any of
    /// them exist, mean that *this* file should be coloured as “compiled”.
    ///
    /// The point of this is to highlight compiled files such as `foo.js` when
    /// their source file `foo.coffee` exists in the same directory.
    /// For example, `foo.js` is perfectly valid without `foo.coffee`, so we
    /// don’t want to always blindly highlight `*.js` as compiled.
    /// (See also `FileExtensions#is_compiled`)
    pub fn get_source_files(&self) -> Vec<PathBuf> {
        if let Some(ext) = &self.ext {
            match &ext[..] {
                "css"   => vec![self.path.with_extension("sass"), self.path.with_extension("scss"),  // SASS, SCSS
                                self.path.with_extension("styl"), self.path.with_extension("less")],  // Stylus, Less
                "js"    => vec![self.path.with_extension("coffee"), self.path.with_extension("ts")],  // CoffeeScript, TypeScript

                "aux" |                                          // TeX: auxiliary file
                "bbl" |                                          // BibTeX bibliography file
                "bcf" |                                          // biblatex control file
                "blg" |                                          // BibTeX log file
                "fdb_latexmk" |                                  // TeX latexmk file
                "fls" |                                          // TeX -recorder file
                "lof" |                                          // TeX list of figures
                "log" |                                          // TeX log file
                "lot" |                                          // TeX list of tables
                "toc" => vec![self.path.with_extension("tex")],  // TeX table of contents

                _ => vec![],  // No source files if none of the above
            }
        }
        else {
            vec![]  // No source files if there’s no extension, either!
        }
    }
}
<|endoftext|>


<commit_before>// A variation on cares-event-loop.rs.
//
// Here we:
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Transform the callback-based c-ares interface into a futures-style.
extern crate c_ares;
extern crate futures;
extern crate mio;
extern crate tokio_core;

use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use self::futures::Future;

// The EventLoop will set up a mio::Poll and use it to wait for the following:
//
// -  messages telling it which file descriptors it should be interested in.
//    These file descriptors are then registered (or deregistered) with the
//    mio::Poll as required.
//
// -  events telling it that something has happened on one of these file
//    descriptors.  When this happens, it tells the c_ares::Channel about it.
//
// -  a message telling it to shut down.
struct EventLoop {
    poll: mio::Poll,
    msg_channel: mio::channel::Receiver<Message>,
    tracked_fds: HashSet<c_ares::Socket>,
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
enum Message {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

// We also use Token(fd) for file descriptors, so this relies on zero not
// being a valid file descriptor for c-ares to use.  Zero is stdin, so that's
// true.
const CHANNEL: mio::Token = mio::Token(0);

impl EventLoop {
    // Create a new event loop.
    pub fn new(
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        rx: mio::channel::Receiver<Message>) -> EventLoop {
        let poll = mio::Poll::new().expect("Failed to create poll");
        poll.register(&rx, CHANNEL, mio::Ready::readable(), mio::PollOpt::edge())
            .expect("failed to register channel with poll");

        EventLoop {
            poll: poll,
            msg_channel: rx,
            tracked_fds: HashSet::<c_ares::Socket>::new(),
            ares_channel: ares_channel,
            quit: false,
        }
    }

    // Run the event loop.
    pub fn run(self) -> thread::JoinHandle<()> {
        thread::spawn(|| self.event_loop_thread())
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = mio::Events::with_capacity(16);
        loop {
            // Wait for something to happen.
            let timeout = Duration::from_millis(500);
            let results = self.poll
                .poll(&mut events, Some(timeout))
                .expect("poll failed");

            // Process whatever happened.
            match results {
                0 => {
                    // No events - must be a timeout.  Tell c-ares about it.
                    self.ares_channel.lock().unwrap().process_fd(
                        c_ares::SOCKET_BAD,
                        c_ares::SOCKET_BAD);
                },
                _ => {
                    // Process events.  One of them might have asked us to quit.
                    for event in &events {
                        self.handle_event(&event);
                        if self.quit { return }
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &mio::Event) {
        match event.token() {
            CHANNEL => {
                // The channel is readable.
                self.handle_messages()
            },

            mio::Token(fd) => {
                // Sockets became readable or writable - tell c-ares.
                let rfd = if event.kind().is_readable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                let wfd = if event.kind().is_writable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
            }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        loop {
            match self.msg_channel.try_recv() {
                Ok(Message::RegisterInterest(fd, readable, writable)) => {
                    // Instruction to do something with a file descriptor.
                    let efd = mio::unix::EventedFd(&fd);
                    if !readable && !writable {
                        self.tracked_fds.remove(&fd);
                        self.poll
                            .deregister(&efd)
                            .expect("failed to deregister interest");
                    } else {
                        let token = mio::Token(fd as usize);
                        let mut interest = mio::Ready::none();
                        if readable { interest.insert(mio::Ready::readable()) }
                        if writable { interest.insert(mio::Ready::writable()) }
                        let register_result = if !self.tracked_fds.insert(fd) {
                            self.poll
                                .reregister(&efd, token, interest, mio::PollOpt::edge())
                        } else {
                            self.poll
                                .register(&efd, token, interest, mio::PollOpt::edge())
                        };
                        register_result.expect("failed to register interest");
                    }
                },

                Ok(Message::ShutDown) => {
                    // Instruction to shut down.
                    self.quit = true;
                    break
                },

                // No more instructions.
                Err(_) => break,
            }
        }
    }
}

// The Resolver is the interface by which users make DNS queries.
struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    event_loop_channel: mio::channel::Sender<Message>,
    event_loop_handle: Option<thread::JoinHandle<()>>,
}

impl Resolver {
    // Create a new Resolver.
    pub fn new() -> Resolver {
        // Whenever c-ares tells us what to do with a file descriptor, we'll
        // send that request along, in a message to the event loop thread.
        let (tx, rx) = mio::channel::channel();
        let tx_clone = tx.clone();
        let sock_callback =
            move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(
                    Message::RegisterInterest(fd, readable, writable));
            };

        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_socket_state_callback(sock_callback)
            .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::new(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and run the event loop.
        let channel_clone = locked_channel.clone();
        let event_loop = EventLoop::new(channel_clone, rx);
        let handle = event_loop.run();

        // Return the Resolver.
        Resolver {
            ares_channel: locked_channel,
            event_loop_channel: tx,
            event_loop_handle: Some(handle),
        }
    }

    // A CNAME query.  Returns a future that will resolve to hold the result.
    pub fn query_cname(&self, name: &str)
        -> futures::BoxFuture<c_ares::CNameResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_cname(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // An MX query.  Returns a future that will resolve to hold the result.
    pub fn query_mx(&self, name: &str)
        -> futures::BoxFuture<c_ares::MXResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_mx(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // A NAPTR query.  Returns a future that will resolve to hold the result.
    pub fn query_naptr(&self, name: &str)
        -> futures::BoxFuture<c_ares::NAPTRResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_naptr(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Shut down the event loop and wait for it to finish.
        self.event_loop_channel
            .send(Message::ShutDown)
            .expect("failed to request event loop to shut down");
        if let Some(handle) = self.event_loop_handle.take() {
           handle.join().expect("failed to shut down event loop");
        }
    }
}

fn print_cname_result(
    result: &Result<c_ares::CNameResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("CNAME lookup failed with error '{}'", e.description());
        }
        Ok(ref cname_results) => {
            println!("Successful CNAME lookup...");
            println!("Hostname: {}", cname_results.hostname());
            for alias in cname_results.aliases() {
                println!("Alias: {}", alias);
            }
        }
    }
}

fn print_mx_results(result: &Result<c_ares::MXResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("MX lookup failed with error '{}'", e.description());
        }
        Ok(ref mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: &Result<c_ares::NAPTRResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("NAPTR lookup failed with error '{}'", e.description());
        }
        Ok(ref naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

pub fn main() {
    // Create a tokio event loop, and a Resolver.  Then make some requests.
    let mut l = tokio_core::reactor::Core::new().unwrap();
    let resolver = Resolver::new();
    let query = resolver.query_cname("dimbleby.github.io");
    let result = l.run(query);
    println!("");
    print_cname_result(&result);

    let query = resolver.query_mx("gmail.com");
    let result = l.run(query);
    println!("");
    print_mx_results(&result);

    let query = resolver.query_naptr("apple.com");
    let result = l.run(query);
    println!("");
    print_naptr_results(&result);
}
<commit_msg>Commenting<commit_after>// A variation on cares-event-loop.rs.
//
// Here we:
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Transform the callback-based c-ares interface into a futures-style.
extern crate c_ares;
extern crate futures;
extern crate mio;
extern crate tokio_core;

use std::collections::HashSet;
use std::error::Error;
use std::sync::{
    Arc,
    Mutex,
};
use std::thread;
use std::time::Duration;

use self::futures::Future;

// The EventLoop will set up a mio::Poll and use it to wait for the following:
//
// -  messages telling it which file descriptors it should be interested in.
//    These file descriptors are then registered (or deregistered) with the
//    mio::Poll as required.
//
// -  events telling it that something has happened on one of these file
//    descriptors.  When this happens, it tells the c_ares::Channel about it.
//
// -  a message telling it to shut down.
struct EventLoop {
    poll: mio::Poll,
    msg_channel: mio::channel::Receiver<Message>,
    tracked_fds: HashSet<c_ares::Socket>,
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    quit: bool,
}

// Messages for the event loop.
#[derive(Debug)]
enum Message {
    // 'Notify me when this file descriptor becomes readable, or writable'.
    // The first bool is for 'readable' and the second is for 'writable'.  It's
    // allowed to set both of these - or neither, meaning 'I am no longer
    // interested in this file descriptor'.
    RegisterInterest(c_ares::Socket, bool, bool),

    // 'Shut down'.
    ShutDown,
}

// A token identifying that the message channel has become available for reading.
//
// We use Token(fd) for file descriptors, so this relies on zero not being a
// valid file descriptor for c-ares to use.  Zero is stdin, so that's true.
const CHANNEL: mio::Token = mio::Token(0);

impl EventLoop {
    // Create a new event loop.
    pub fn new(
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        rx: mio::channel::Receiver<Message>) -> EventLoop {
        let poll = mio::Poll::new().expect("Failed to create poll");
        poll.register(&rx, CHANNEL, mio::Ready::readable(), mio::PollOpt::edge())
            .expect("failed to register channel with poll");

        EventLoop {
            poll: poll,
            msg_channel: rx,
            tracked_fds: HashSet::<c_ares::Socket>::new(),
            ares_channel: ares_channel,
            quit: false,
        }
    }

    // Run the event loop.
    pub fn run(self) -> thread::JoinHandle<()> {
        thread::spawn(|| self.event_loop_thread())
    }

    // Event loop thread - waits for events, and handles them.
    fn event_loop_thread(mut self) {
        let mut events = mio::Events::with_capacity(16);
        loop {
            // Wait for something to happen.
            let timeout = Duration::from_millis(500);
            let results = self.poll
                .poll(&mut events, Some(timeout))
                .expect("poll failed");

            // Process whatever happened.
            match results {
                0 => {
                    // No events - must be a timeout.  Tell c-ares about it.
                    self.ares_channel.lock().unwrap().process_fd(
                        c_ares::SOCKET_BAD,
                        c_ares::SOCKET_BAD);
                },
                _ => {
                    // Process events.  One of them might have asked us to quit.
                    for event in &events {
                        self.handle_event(&event);
                        if self.quit { return }
                    }
                }
            }
        }
    }

    // Handle a single event.
    fn handle_event(&mut self, event: &mio::Event) {
        match event.token() {
            CHANNEL => {
                // The channel is readable.
                self.handle_messages()
            },

            mio::Token(fd) => {
                // Sockets became readable or writable - tell c-ares.
                let rfd = if event.kind().is_readable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                let wfd = if event.kind().is_writable() {
                    fd as c_ares::Socket
                } else {
                    c_ares::SOCKET_BAD
                };
                self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
            }
        }
    }

    // Process messages incoming on the channel.
    fn handle_messages(&mut self) {
        loop {
            match self.msg_channel.try_recv() {
                Ok(Message::RegisterInterest(fd, readable, writable)) => {
                    // Instruction to do something with a file descriptor.
                    let efd = mio::unix::EventedFd(&fd);
                    if !readable && !writable {
                        self.tracked_fds.remove(&fd);
                        self.poll
                            .deregister(&efd)
                            .expect("failed to deregister interest");
                    } else {
                        let token = mio::Token(fd as usize);
                        let mut interest = mio::Ready::none();
                        if readable { interest.insert(mio::Ready::readable()) }
                        if writable { interest.insert(mio::Ready::writable()) }
                        let register_result = if !self.tracked_fds.insert(fd) {
                            self.poll
                                .reregister(&efd, token, interest, mio::PollOpt::edge())
                        } else {
                            self.poll
                                .register(&efd, token, interest, mio::PollOpt::edge())
                        };
                        register_result.expect("failed to register interest");
                    }
                },

                Ok(Message::ShutDown) => {
                    // Instruction to shut down.
                    self.quit = true;
                    break
                },

                // No more instructions.
                Err(_) => break,
            }
        }
    }
}

// The Resolver is the interface by which users make DNS queries.
struct Resolver {
    ares_channel: Arc<Mutex<c_ares::Channel>>,
    event_loop_channel: mio::channel::Sender<Message>,
    event_loop_handle: Option<thread::JoinHandle<()>>,
}

impl Resolver {
    // Create a new Resolver.
    pub fn new() -> Resolver {
        // Whenever c-ares tells us what to do with a file descriptor, we'll
        // send that request along, in a message to the event loop thread.
        let (tx, rx) = mio::channel::channel();
        let tx_clone = tx.clone();
        let sock_callback =
            move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(
                    Message::RegisterInterest(fd, readable, writable));
            };

        // Create a c_ares::Channel.
        let mut options = c_ares::Options::new();
        options
            .set_socket_state_callback(sock_callback)
            .set_flags(c_ares::flags::STAYOPEN | c_ares::flags::EDNS)
            .set_timeout(500)
            .set_tries(3);
        let mut ares_channel = c_ares::Channel::new(options)
            .expect("Failed to create channel");
        ares_channel.set_servers(&["8.8.8.8"]).expect("Failed to set servers");
        let locked_channel = Arc::new(Mutex::new(ares_channel));

        // Create and run the event loop.
        let channel_clone = locked_channel.clone();
        let event_loop = EventLoop::new(channel_clone, rx);
        let handle = event_loop.run();

        // Return the Resolver.
        Resolver {
            ares_channel: locked_channel,
            event_loop_channel: tx,
            event_loop_handle: Some(handle),
        }
    }

    // A CNAME query.  Returns a future that will resolve to hold the result.
    pub fn query_cname(&self, name: &str)
        -> futures::BoxFuture<c_ares::CNameResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_cname(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // An MX query.  Returns a future that will resolve to hold the result.
    pub fn query_mx(&self, name: &str)
        -> futures::BoxFuture<c_ares::MXResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_mx(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }

    // A NAPTR query.  Returns a future that will resolve to hold the result.
    pub fn query_naptr(&self, name: &str)
        -> futures::BoxFuture<c_ares::NAPTRResults, c_ares::AresError> {
        let (c, p) = futures::oneshot();
        self.ares_channel.lock().unwrap().query_naptr(name, move |result| {
            c.complete(result);
        });
        p.map_err(|_| c_ares::AresError::ECANCELLED)
            .and_then(futures::done)
            .boxed()
    }
}

impl Drop for Resolver {
    fn drop(&mut self) {
        // Shut down the event loop and wait for it to finish.
        self.event_loop_channel
            .send(Message::ShutDown)
            .expect("failed to request event loop to shut down");
        if let Some(handle) = self.event_loop_handle.take() {
           handle.join().expect("failed to shut down event loop");
        }
    }
}

fn print_cname_result(
    result: &Result<c_ares::CNameResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("CNAME lookup failed with error '{}'", e.description());
        }
        Ok(ref cname_results) => {
            println!("Successful CNAME lookup...");
            println!("Hostname: {}", cname_results.hostname());
            for alias in cname_results.aliases() {
                println!("Alias: {}", alias);
            }
        }
    }
}

fn print_mx_results(result: &Result<c_ares::MXResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("MX lookup failed with error '{}'", e.description());
        }
        Ok(ref mx_results) => {
            println!("Successful MX lookup...");
            for mx_result in mx_results {
                println!(
                    "host {}, priority {}",
                    mx_result.host(),
                    mx_result.priority());
            }
        }
    }
}

fn print_naptr_results(
    result: &Result<c_ares::NAPTRResults, c_ares::AresError>) {
    match *result {
        Err(ref e) => {
            println!("NAPTR lookup failed with error '{}'", e.description());
        }
        Ok(ref naptr_results) => {
            println!("Successful NAPTR lookup...");
            for naptr_result in naptr_results {
                println!("flags: {}", naptr_result.flags());
                println!("service name: {}", naptr_result.service_name());
                println!("regular expression: {}", naptr_result.reg_exp());
                println!(
                    "replacement pattern: {}",
                    naptr_result.replacement_pattern());
                println!("order: {}", naptr_result.order());
                println!("preference: {}", naptr_result.preference());
            }
        }
    }
}

pub fn main() {
    // Create a tokio event loop, and a Resolver.  Then make some requests.
    let mut l = tokio_core::reactor::Core::new().unwrap();
    let resolver = Resolver::new();
    let query = resolver.query_cname("dimbleby.github.io");
    let result = l.run(query);
    println!("");
    print_cname_result(&result);

    let query = resolver.query_mx("gmail.com");
    let result = l.run(query);
    println!("");
    print_mx_results(&result);

    let query = resolver.query_naptr("apple.com");
    let result = l.run(query);
    println!("");
    print_naptr_results(&result);
}
<|endoftext|>


<commit_before>mod cursor;
pub mod raw;
#[doc(hidden)]
pub mod result;
mod row;
mod stmt;

use std::ffi::CString;
use std::os::raw as libc;

use self::cursor::*;
use self::raw::RawConnection;
use self::result::PgResult;
use self::stmt::Statement;
use crate::connection::*;
use crate::deserialize::FromSqlRow;
use crate::expression::QueryMetadata;
use crate::pg::{metadata_lookup::{PgMetadataCache}, Pg, TransactionBuilder};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::*;
use crate::result::ConnectionError::CouldntSetupConfiguration;
use crate::result::Error::DeserializationError;
use crate::result::*;

/// The connection string expected by `PgConnection::establish`
/// should be a PostgreSQL connection string, as documented at
/// <https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING>
#[allow(missing_debug_implementations)]
pub struct PgConnection {
    pub(crate) raw_connection: RawConnection,
    pub(crate) transaction_manager: AnsiTransactionManager,
    statement_cache: StatementCache<Pg, Statement>,
    metadata_cache: PgMetadataCache,
}

unsafe impl Send for PgConnection {}

impl SimpleConnection for PgConnection {
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        let query = CString::new(query)?;
        let inner_result = unsafe { self.raw_connection.exec(query.as_ptr()) };
        PgResult::new(inner_result?)?;
        Ok(())
    }
}

impl Connection for PgConnection {
    type Backend = Pg;
    type TransactionManager = AnsiTransactionManager;

    fn establish(database_url: &str) -> ConnectionResult<PgConnection> {
        RawConnection::establish(database_url).and_then(|raw_conn| {
            let conn = PgConnection {
                raw_connection: raw_conn,
                transaction_manager: AnsiTransactionManager::new(),
                statement_cache: StatementCache::new(),
                metadata_cache: PgMetadataCache::new(),
            };
            conn.set_config_options()
                .map_err(CouldntSetupConfiguration)?;
            Ok(conn)
        })
    }

    #[doc(hidden)]
    fn execute(&self, query: &str) -> QueryResult<usize> {
        self.execute_inner(query).map(|res| res.rows_affected())
    }

    #[doc(hidden)]
    fn load<T, U>(&self, source: T) -> QueryResult<Vec<U>>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        U: FromSqlRow<T::SqlType, Self::Backend>,
        Self::Backend: QueryMetadata<T::SqlType>,
    {
        let (query, params) = self.prepare_query(&source.as_query())?;
        let result = query.execute(self, &params)?;
        let cursor = Cursor::new(&result);

        cursor
            .map(|row| U::build_from_row(&row).map_err(DeserializationError))
            .collect::<QueryResult<Vec<_>>>()
    }

    #[doc(hidden)]
    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize>
    where
        T: QueryFragment<Pg> + QueryId,
    {
        let (query, params) = self.prepare_query(source)?;
        query.execute(self, &params).map(|r| r.rows_affected())
    }

    #[doc(hidden)]
    fn transaction_manager(&self) -> &Self::TransactionManager {
        &self.transaction_manager
    }
}

impl PgConnection {
    /// Build a transaction, specifying additional details such as isolation level
    ///
    /// See [`TransactionBuilder`] for more examples.
    ///
    /// [`TransactionBuilder`]: ../pg/struct.TransactionBuilder.html
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let conn = connection_no_transaction();
    /// conn.build_transaction()
    ///     .read_only()
    ///     .serializable()
    ///     .deferrable()
    ///     .run(|| Ok(()))
    /// # }
    /// ```
    pub fn build_transaction(&self) -> TransactionBuilder {
        TransactionBuilder::new(self)
    }

    #[allow(clippy::type_complexity)]
    fn prepare_query<T: QueryFragment<Pg> + QueryId>(
        &self,
        source: &T,
    ) -> QueryResult<(MaybeCached<Statement>, Vec<Option<Vec<u8>>>)> {
        let mut bind_collector = RawBytesBindCollector::<Pg>::new();
        source.collect_binds(&mut bind_collector, self)?;
        let binds = bind_collector.binds;
        let metadata = bind_collector.metadata;

        let cache_len = self.statement_cache.len();
        let query = self
            .statement_cache
            .cached_statement(source, &metadata, |sql| {
                let query_name = if source.is_safe_to_cache_prepared()? {
                    Some(format!("__diesel_stmt_{}", cache_len))
                } else {
                    None
                };
                Statement::prepare(self, sql, query_name.as_ref().map(|s| &**s), &metadata)
            });

        Ok((query?, binds))
    }

    fn execute_inner(&self, query: &str) -> QueryResult<PgResult> {
        let query = Statement::prepare(self, query, None, &[])?;
        query.execute(self, &Vec::new())
    }

    fn set_config_options(&self) -> QueryResult<()> {
        self.execute("SET TIME ZONE 'UTC'")?;
        self.execute("SET CLIENT_ENCODING TO 'UTF8'")?;
        self.raw_connection
            .set_notice_processor(noop_notice_processor);
        Ok(())
    }

    pub(crate) fn get_metadata_cache(&self) -> &PgMetadataCache {
        &self.metadata_cache
    }
}

extern "C" fn noop_notice_processor(_: *mut libc::c_void, _message: *const libc::c_char) {}

#[cfg(test)]
mod tests {
    extern crate dotenv;

    use self::dotenv::dotenv;
    use std::env;

    use super::*;
    use crate::dsl::sql;
    use crate::prelude::*;
    use crate::sql_types::{Integer, VarChar};

    #[test]
    fn prepared_statements_are_cached() {
        let connection = connection();

        let query = crate::select(1.into_sql::<Integer>());

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(1, connection.statement_cache.len());
    }

    #[test]
    fn queries_with_identical_sql_but_different_types_are_cached_separately() {
        let connection = connection();

        let query = crate::select(1.into_sql::<Integer>());
        let query2 = crate::select("hi".into_sql::<VarChar>());

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok("hi".to_string()), query2.get_result(&connection));
        assert_eq!(2, connection.statement_cache.len());
    }

    #[test]
    fn queries_with_identical_types_and_sql_but_different_bind_types_are_cached_separately() {
        let connection = connection();

        let query = crate::select(1.into_sql::<Integer>()).into_boxed::<Pg>();
        let query2 = crate::select("hi".into_sql::<VarChar>()).into_boxed::<Pg>();

        assert_eq!(0, connection.statement_cache.len());
        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok("hi".to_string()), query2.get_result(&connection));
        assert_eq!(2, connection.statement_cache.len());
    }

    sql_function!(fn lower(x: VarChar) -> VarChar);

    #[test]
    fn queries_with_identical_types_and_binds_but_different_sql_are_cached_separately() {
        let connection = connection();

        let hi = "HI".into_sql::<VarChar>();
        let query = crate::select(hi).into_boxed::<Pg>();
        let query2 = crate::select(lower(hi)).into_boxed::<Pg>();

        assert_eq!(0, connection.statement_cache.len());
        assert_eq!(Ok("HI".to_string()), query.get_result(&connection));
        assert_eq!(Ok("hi".to_string()), query2.get_result(&connection));
        assert_eq!(2, connection.statement_cache.len());
    }

    #[test]
    fn queries_with_sql_literal_nodes_are_not_cached() {
        let connection = connection();
        let query = crate::select(sql::<Integer>("1"));

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.len());
    }

    fn connection() -> PgConnection {
        dotenv().ok();
        let database_url = env::var("PG_DATABASE_URL")
            .or_else(|_| env::var("DATABASE_URL"))
            .expect("DATABASE_URL must be set in order to run tests");
        PgConnection::establish(&database_url).unwrap()
    }
}
<commit_msg>style: :art: ran rust fmt<commit_after>mod cursor;
pub mod raw;
#[doc(hidden)]
pub mod result;
mod row;
mod stmt;

use std::ffi::CString;
use std::os::raw as libc;

use self::cursor::*;
use self::raw::RawConnection;
use self::result::PgResult;
use self::stmt::Statement;
use crate::connection::*;
use crate::deserialize::FromSqlRow;
use crate::expression::QueryMetadata;
use crate::pg::{metadata_lookup::PgMetadataCache, Pg, TransactionBuilder};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::*;
use crate::result::ConnectionError::CouldntSetupConfiguration;
use crate::result::Error::DeserializationError;
use crate::result::*;

/// The connection string expected by `PgConnection::establish`
/// should be a PostgreSQL connection string, as documented at
/// <https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING>
#[allow(missing_debug_implementations)]
pub struct PgConnection {
    pub(crate) raw_connection: RawConnection,
    pub(crate) transaction_manager: AnsiTransactionManager,
    statement_cache: StatementCache<Pg, Statement>,
    metadata_cache: PgMetadataCache,
}

unsafe impl Send for PgConnection {}

impl SimpleConnection for PgConnection {
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        let query = CString::new(query)?;
        let inner_result = unsafe { self.raw_connection.exec(query.as_ptr()) };
        PgResult::new(inner_result?)?;
        Ok(())
    }
}

impl Connection for PgConnection {
    type Backend = Pg;
    type TransactionManager = AnsiTransactionManager;

    fn establish(database_url: &str) -> ConnectionResult<PgConnection> {
        RawConnection::establish(database_url).and_then(|raw_conn| {
            let conn = PgConnection {
                raw_connection: raw_conn,
                transaction_manager: AnsiTransactionManager::new(),
                statement_cache: StatementCache::new(),
                metadata_cache: PgMetadataCache::new(),
            };
            conn.set_config_options()
                .map_err(CouldntSetupConfiguration)?;
            Ok(conn)
        })
    }

    #[doc(hidden)]
    fn execute(&self, query: &str) -> QueryResult<usize> {
        self.execute_inner(query).map(|res| res.rows_affected())
    }

    #[doc(hidden)]
    fn load<T, U>(&self, source: T) -> QueryResult<Vec<U>>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        U: FromSqlRow<T::SqlType, Self::Backend>,
        Self::Backend: QueryMetadata<T::SqlType>,
    {
        let (query, params) = self.prepare_query(&source.as_query())?;
        let result = query.execute(self, &params)?;
        let cursor = Cursor::new(&result);

        cursor
            .map(|row| U::build_from_row(&row).map_err(DeserializationError))
            .collect::<QueryResult<Vec<_>>>()
    }

    #[doc(hidden)]
    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize>
    where
        T: QueryFragment<Pg> + QueryId,
    {
        let (query, params) = self.prepare_query(source)?;
        query.execute(self, &params).map(|r| r.rows_affected())
    }

    #[doc(hidden)]
    fn transaction_manager(&self) -> &Self::TransactionManager {
        &self.transaction_manager
    }
}

impl PgConnection {
    /// Build a transaction, specifying additional details such as isolation level
    ///
    /// See [`TransactionBuilder`] for more examples.
    ///
    /// [`TransactionBuilder`]: ../pg/struct.TransactionBuilder.html
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let conn = connection_no_transaction();
    /// conn.build_transaction()
    ///     .read_only()
    ///     .serializable()
    ///     .deferrable()
    ///     .run(|| Ok(()))
    /// # }
    /// ```
    pub fn build_transaction(&self) -> TransactionBuilder {
        TransactionBuilder::new(self)
    }

    #[allow(clippy::type_complexity)]
    fn prepare_query<T: QueryFragment<Pg> + QueryId>(
        &self,
        source: &T,
    ) -> QueryResult<(MaybeCached<Statement>, Vec<Option<Vec<u8>>>)> {
        let mut bind_collector = RawBytesBindCollector::<Pg>::new();
        source.collect_binds(&mut bind_collector, self)?;
        let binds = bind_collector.binds;
        let metadata = bind_collector.metadata;

        let cache_len = self.statement_cache.len();
        let query = self
            .statement_cache
            .cached_statement(source, &metadata, |sql| {
                let query_name = if source.is_safe_to_cache_prepared()? {
                    Some(format!("__diesel_stmt_{}", cache_len))
                } else {
                    None
                };
                Statement::prepare(self, sql, query_name.as_ref().map(|s| &**s), &metadata)
            });

        Ok((query?, binds))
    }

    fn execute_inner(&self, query: &str) -> QueryResult<PgResult> {
        let query = Statement::prepare(self, query, None, &[])?;
        query.execute(self, &Vec::new())
    }

    fn set_config_options(&self) -> QueryResult<()> {
        self.execute("SET TIME ZONE 'UTC'")?;
        self.execute("SET CLIENT_ENCODING TO 'UTF8'")?;
        self.raw_connection
            .set_notice_processor(noop_notice_processor);
        Ok(())
    }

    pub(crate) fn get_metadata_cache(&self) -> &PgMetadataCache {
        &self.metadata_cache
    }
}

extern "C" fn noop_notice_processor(_: *mut libc::c_void, _message: *const libc::c_char) {}

#[cfg(test)]
mod tests {
    extern crate dotenv;

    use self::dotenv::dotenv;
    use std::env;

    use super::*;
    use crate::dsl::sql;
    use crate::prelude::*;
    use crate::sql_types::{Integer, VarChar};

    #[test]
    fn prepared_statements_are_cached() {
        let connection = connection();

        let query = crate::select(1.into_sql::<Integer>());

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(1, connection.statement_cache.len());
    }

    #[test]
    fn queries_with_identical_sql_but_different_types_are_cached_separately() {
        let connection = connection();

        let query = crate::select(1.into_sql::<Integer>());
        let query2 = crate::select("hi".into_sql::<VarChar>());

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok("hi".to_string()), query2.get_result(&connection));
        assert_eq!(2, connection.statement_cache.len());
    }

    #[test]
    fn queries_with_identical_types_and_sql_but_different_bind_types_are_cached_separately() {
        let connection = connection();

        let query = crate::select(1.into_sql::<Integer>()).into_boxed::<Pg>();
        let query2 = crate::select("hi".into_sql::<VarChar>()).into_boxed::<Pg>();

        assert_eq!(0, connection.statement_cache.len());
        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok("hi".to_string()), query2.get_result(&connection));
        assert_eq!(2, connection.statement_cache.len());
    }

    sql_function!(fn lower(x: VarChar) -> VarChar);

    #[test]
    fn queries_with_identical_types_and_binds_but_different_sql_are_cached_separately() {
        let connection = connection();

        let hi = "HI".into_sql::<VarChar>();
        let query = crate::select(hi).into_boxed::<Pg>();
        let query2 = crate::select(lower(hi)).into_boxed::<Pg>();

        assert_eq!(0, connection.statement_cache.len());
        assert_eq!(Ok("HI".to_string()), query.get_result(&connection));
        assert_eq!(Ok("hi".to_string()), query2.get_result(&connection));
        assert_eq!(2, connection.statement_cache.len());
    }

    #[test]
    fn queries_with_sql_literal_nodes_are_not_cached() {
        let connection = connection();
        let query = crate::select(sql::<Integer>("1"));

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.len());
    }

    fn connection() -> PgConnection {
        dotenv().ok();
        let database_url = env::var("PG_DATABASE_URL")
            .or_else(|_| env::var("DATABASE_URL"))
            .expect("DATABASE_URL must be set in order to run tests");
        PgConnection::establish(&database_url).unwrap()
    }
}
<|endoftext|>