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

//! Support for inlining external documentation into the current AST.

use syntax::ast;
use syntax::ast_util;
use syntax::attr::AttrMetaMethods;

use rustc::metadata::csearch;
use rustc::metadata::decoder;
use rustc::middle::ty;

use core;
use doctree;
use clean;

use super::Clean;

/// Attempt to inline the definition of a local node id into this AST.
///
/// This function will fetch the definition of the id specified, and if it is
/// from another crate it will attempt to inline the documentation from the
/// other crate into this crate.
///
/// This is primarily used for `pub use` statements which are, in general,
/// implementation details. Inlining the documentation should help provide a
/// better experience when reading the documentation in this use case.
///
/// The returned value is `None` if the `id` could not be inlined, and `Some`
/// of a vector of items if it was successfully expanded.
pub fn try_inline(id: ast::NodeId) -> Option<Vec<clean::Item>> {
    let cx = ::ctxtkey.get().unwrap();
    let tcx = match cx.maybe_typed {
        core::Typed(ref tycx) => tycx,
        core::NotTyped(_) => return None,
    };
    let def = match tcx.def_map.borrow().find(&id) {
        Some(def) => *def,
        None => return None,
    };
    let did = ast_util::def_id_of_def(def);
    if ast_util::is_local(did) { return None }
    try_inline_def(&**cx, tcx, def)
}

fn try_inline_def(cx: &core::DocContext,
                  tcx: &ty::ctxt,
                  def: ast::Def) -> Option<Vec<clean::Item>> {
    let mut ret = Vec::new();
    let did = ast_util::def_id_of_def(def);
    let inner = match def {
        ast::DefTrait(did) => {
            record_extern_fqn(cx, did, clean::TypeTrait);
            clean::TraitItem(build_external_trait(tcx, did))
        }
        ast::DefFn(did, style) => {
            // If this function is a tuple struct constructor, we just skip it
            if csearch::get_tuple_struct_definition_if_ctor(&tcx.sess.cstore,
                                                            did).is_some() {
                return None
            }
            record_extern_fqn(cx, did, clean::TypeFunction);
            clean::FunctionItem(build_external_function(tcx, did, style))
        }
        ast::DefStruct(did) => {
            record_extern_fqn(cx, did, clean::TypeStruct);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            clean::StructItem(build_struct(tcx, did))
        }
        ast::DefTy(did) => {
            record_extern_fqn(cx, did, clean::TypeEnum);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            build_type(tcx, did)
        }
        // Assume that the enum type is reexported next to the variant, and
        // variants don't show up in documentation specially.
        ast::DefVariant(..) => return Some(Vec::new()),
        ast::DefMod(did) => {
            record_extern_fqn(cx, did, clean::TypeModule);
            clean::ModuleItem(build_module(cx, tcx, did))
        }
        _ => return None,
    };
    let fqn = csearch::get_item_path(tcx, did);
    cx.inlined.borrow_mut().get_mut_ref().insert(did);
    ret.push(clean::Item {
        source: clean::Span::empty(),
        name: Some(fqn.last().unwrap().to_str().to_string()),
        attrs: load_attrs(tcx, did),
        inner: inner,
        visibility: Some(ast::Public),
        def_id: did,
    });
    Some(ret)
}

pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec<clean::Attribute> {
    let mut attrs = Vec::new();
    csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
        attrs.extend(v.move_iter().map(|mut a| {
            // FIXME this isn't quite always true, it's just true about 99% of
            //       the time when dealing with documentation. For example,
            //       this would treat doc comments of the form `#[doc = "foo"]`
            //       incorrectly.
            if a.name().get() == "doc" && a.value_str().is_some() {
                a.node.is_sugared_doc = true;
            }
            a.clean()
        }));
    });
    attrs
}

/// Record an external fully qualified name in the external_paths cache.
///
/// These names are used later on by HTML rendering to generate things like
/// source links back to the original item.
pub fn record_extern_fqn(cx: &core::DocContext,
                         did: ast::DefId,
                         kind: clean::TypeKind) {
    match cx.maybe_typed {
        core::Typed(ref tcx) => {
            let fqn = csearch::get_item_path(tcx, did);
            let fqn = fqn.move_iter().map(|i| i.to_str()).collect();
            cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
        }
        core::NotTyped(..) => {}
    }
}

pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
    let def = ty::lookup_trait_def(tcx, did);
    let methods = ty::trait_methods(tcx, did).clean();
    let provided = ty::provided_trait_methods(tcx, did);
    let mut methods = methods.move_iter().map(|meth| {
        if provided.iter().any(|a| a.def_id == meth.def_id) {
            clean::Provided(meth)
        } else {
            clean::Required(meth)
        }
    });
    clean::Trait {
        generics: def.generics.clean(),
        methods: methods.collect(),
        parents: Vec::new(), // FIXME: this is likely wrong
    }
}

fn build_external_function(tcx: &ty::ctxt,
                           did: ast::DefId,
                           style: ast::FnStyle) -> clean::Function {
    let t = ty::lookup_item_type(tcx, did);
    clean::Function {
        decl: match ty::get(t.ty).sty {
            ty::ty_bare_fn(ref f) => (did, &f.sig).clean(),
            _ => fail!("bad function"),
        },
        generics: t.generics.clean(),
        fn_style: style,
    }
}

fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct {
    use syntax::parse::token::special_idents::unnamed_field;

    let t = ty::lookup_item_type(tcx, did);
    let fields = ty::lookup_struct_fields(tcx, did);

    clean::Struct {
        struct_type: match fields.as_slice() {
            [] => doctree::Unit,
            [ref f] if f.name == unnamed_field.name => doctree::Newtype,
            [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple,
            _ => doctree::Plain,
        },
        generics: t.generics.clean(),
        fields: fields.iter().map(|f| f.clean()).collect(),
        fields_stripped: false,
    }
}

fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
    let t = ty::lookup_item_type(tcx, did);
    match ty::get(t.ty).sty {
        ty::ty_enum(edid, _) => {
            return clean::EnumItem(clean::Enum {
                generics: t.generics.clean(),
                variants_stripped: false,
                variants: ty::enum_variants(tcx, edid).clean(),
            })
        }
        _ => {}
    }

    clean::TypedefItem(clean::Typedef {
        type_: t.ty.clean(),
        generics: t.generics.clean(),
    })
}

fn build_impls(cx: &core::DocContext,
               tcx: &ty::ctxt,
               did: ast::DefId) -> Vec<clean::Item> {
    ty::populate_implementations_for_type_if_necessary(tcx, did);
    let mut impls = Vec::new();

    match tcx.inherent_impls.borrow().find(&did) {
        None => {}
        Some(i) => {
            impls.extend(i.borrow().iter().map(|&did| { build_impl(cx, tcx, did) }));
        }
    }

    // If this is the first time we've inlined something from this crate, then
    // we inline *all* impls from the crate into this crate. Note that there's
    // currently no way for us to filter this based on type, and we likely need
    // many impls for a variety of reasons.
    //
    // Primarily, the impls will be used to populate the documentation for this
    // type being inlined, but impls can also be used when generating
    // documentation for primitives (no way to find those specifically).
    if cx.populated_crate_impls.borrow_mut().insert(did.krate) {
        csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
                                              did.krate,
                                              |def, _, _| {
            populate_impls(cx, tcx, def, &mut impls)
        });

        fn populate_impls(cx: &core::DocContext,
                          tcx: &ty::ctxt,
                          def: decoder::DefLike,
                          impls: &mut Vec<Option<clean::Item>>) {
            match def {
                decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)),
                decoder::DlDef(ast::DefMod(did)) => {
                    csearch::each_child_of_item(&tcx.sess.cstore,
                                                did,
                                                |def, _, _| {
                        populate_impls(cx, tcx, def, impls)
                    })
                }
                _ => {}
            }
        }
    }

    impls.move_iter().filter_map(|a| a).collect()
}

fn build_impl(cx: &core::DocContext,
              tcx: &ty::ctxt,
              did: ast::DefId) -> Option<clean::Item> {
    if !cx.inlined.borrow_mut().get_mut_ref().insert(did) {
        return None
    }

    let associated_trait = csearch::get_impl_trait(tcx, did);
    let attrs = load_attrs(tcx, did);
    let ty = ty::lookup_item_type(tcx, did);
    let methods = csearch::get_impl_methods(&tcx.sess.cstore,
                                            did).iter().filter_map(|did| {
        let method = ty::method(tcx, *did);
        if method.vis != ast::Public && associated_trait.is_none() {
            return None
        }
        let mut item = ty::method(tcx, *did).clean();
        item.inner = match item.inner.clone() {
            clean::TyMethodItem(clean::TyMethod {
                fn_style, decl, self_, generics
            }) => {
                clean::MethodItem(clean::Method {
                    fn_style: fn_style,
                    decl: decl,
                    self_: self_,
                    generics: generics,
                })
            }
            _ => fail!("not a tymethod"),
        };
        Some(item)
    }).collect();
    Some(clean::Item {
        inner: clean::ImplItem(clean::Impl {
            derived: clean::detect_derived(attrs.as_slice()),
            trait_: associated_trait.clean().map(|bound| {
                match bound {
                    clean::TraitBound(ty) => ty,
                    clean::RegionBound => unreachable!(),
                }
            }),
            for_: ty.ty.clean(),
            generics: ty.generics.clean(),
            methods: methods,
        }),
        source: clean::Span::empty(),
        name: None,
        attrs: attrs,
        visibility: Some(ast::Inherited),
        def_id: did,
    })
}

fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
                did: ast::DefId) -> clean::Module {
    let mut items = Vec::new();

    // FIXME: this doesn't handle reexports inside the module itself.
    //        Should they be handled?
    csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| {
        if vis != ast::Public { return }
        match def {
            decoder::DlDef(def) => {
                match try_inline_def(cx, tcx, def) {
                    Some(i) => items.extend(i.move_iter()),
                    None => {}
                }
            }
            // All impls were inlined above
            decoder::DlImpl(..) => {}
            decoder::DlField => fail!("unimplemented field"),
        }
    });

    clean::Module {
        items: items,
        is_crate: false,
    }
}
<commit_msg>auto merge of #14640 : tomjakubowski/rust/fix-14636, r=huonw<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for inlining external documentation into the current AST.

use syntax::ast;
use syntax::ast_util;
use syntax::attr::AttrMetaMethods;

use rustc::metadata::csearch;
use rustc::metadata::decoder;
use rustc::middle::ty;

use core;
use doctree;
use clean;

use super::Clean;

/// Attempt to inline the definition of a local node id into this AST.
///
/// This function will fetch the definition of the id specified, and if it is
/// from another crate it will attempt to inline the documentation from the
/// other crate into this crate.
///
/// This is primarily used for `pub use` statements which are, in general,
/// implementation details. Inlining the documentation should help provide a
/// better experience when reading the documentation in this use case.
///
/// The returned value is `None` if the `id` could not be inlined, and `Some`
/// of a vector of items if it was successfully expanded.
pub fn try_inline(id: ast::NodeId) -> Option<Vec<clean::Item>> {
    let cx = ::ctxtkey.get().unwrap();
    let tcx = match cx.maybe_typed {
        core::Typed(ref tycx) => tycx,
        core::NotTyped(_) => return None,
    };
    let def = match tcx.def_map.borrow().find(&id) {
        Some(def) => *def,
        None => return None,
    };
    let did = ast_util::def_id_of_def(def);
    if ast_util::is_local(did) { return None }
    try_inline_def(&**cx, tcx, def)
}

fn try_inline_def(cx: &core::DocContext,
                  tcx: &ty::ctxt,
                  def: ast::Def) -> Option<Vec<clean::Item>> {
    let mut ret = Vec::new();
    let did = ast_util::def_id_of_def(def);
    let inner = match def {
        ast::DefTrait(did) => {
            record_extern_fqn(cx, did, clean::TypeTrait);
            clean::TraitItem(build_external_trait(tcx, did))
        }
        ast::DefFn(did, style) => {
            // If this function is a tuple struct constructor, we just skip it
            if csearch::get_tuple_struct_definition_if_ctor(&tcx.sess.cstore,
                                                            did).is_some() {
                return None
            }
            record_extern_fqn(cx, did, clean::TypeFunction);
            clean::FunctionItem(build_external_function(tcx, did, style))
        }
        ast::DefStruct(did) => {
            record_extern_fqn(cx, did, clean::TypeStruct);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            clean::StructItem(build_struct(tcx, did))
        }
        ast::DefTy(did) => {
            record_extern_fqn(cx, did, clean::TypeEnum);
            ret.extend(build_impls(cx, tcx, did).move_iter());
            build_type(tcx, did)
        }
        // Assume that the enum type is reexported next to the variant, and
        // variants don't show up in documentation specially.
        ast::DefVariant(..) => return Some(Vec::new()),
        ast::DefMod(did) => {
            record_extern_fqn(cx, did, clean::TypeModule);
            clean::ModuleItem(build_module(cx, tcx, did))
        }
        _ => return None,
    };
    let fqn = csearch::get_item_path(tcx, did);
    cx.inlined.borrow_mut().get_mut_ref().insert(did);
    ret.push(clean::Item {
        source: clean::Span::empty(),
        name: Some(fqn.last().unwrap().to_str().to_string()),
        attrs: load_attrs(tcx, did),
        inner: inner,
        visibility: Some(ast::Public),
        def_id: did,
    });
    Some(ret)
}

pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec<clean::Attribute> {
    let mut attrs = Vec::new();
    csearch::get_item_attrs(&tcx.sess.cstore, did, |v| {
        attrs.extend(v.move_iter().map(|mut a| {
            // FIXME this isn't quite always true, it's just true about 99% of
            //       the time when dealing with documentation. For example,
            //       this would treat doc comments of the form `#[doc = "foo"]`
            //       incorrectly.
            if a.name().get() == "doc" && a.value_str().is_some() {
                a.node.is_sugared_doc = true;
            }
            a.clean()
        }));
    });
    attrs
}

/// Record an external fully qualified name in the external_paths cache.
///
/// These names are used later on by HTML rendering to generate things like
/// source links back to the original item.
pub fn record_extern_fqn(cx: &core::DocContext,
                         did: ast::DefId,
                         kind: clean::TypeKind) {
    match cx.maybe_typed {
        core::Typed(ref tcx) => {
            let fqn = csearch::get_item_path(tcx, did);
            let fqn = fqn.move_iter().map(|i| i.to_str()).collect();
            cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
        }
        core::NotTyped(..) => {}
    }
}

pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
    let def = ty::lookup_trait_def(tcx, did);
    let methods = ty::trait_methods(tcx, did).clean();
    let provided = ty::provided_trait_methods(tcx, did);
    let mut methods = methods.move_iter().map(|meth| {
        if provided.iter().any(|a| a.def_id == meth.def_id) {
            clean::Provided(meth)
        } else {
            clean::Required(meth)
        }
    });
    let supertraits = ty::trait_supertraits(tcx, did);
    let mut parents = supertraits.iter().map(|i| {
        match i.clean() {
            clean::TraitBound(ty) => ty,
            clean::RegionBound => unreachable!()
        }
    });

    clean::Trait {
        generics: def.generics.clean(),
        methods: methods.collect(),
        parents: parents.collect()
    }
}

fn build_external_function(tcx: &ty::ctxt,
                           did: ast::DefId,
                           style: ast::FnStyle) -> clean::Function {
    let t = ty::lookup_item_type(tcx, did);
    clean::Function {
        decl: match ty::get(t.ty).sty {
            ty::ty_bare_fn(ref f) => (did, &f.sig).clean(),
            _ => fail!("bad function"),
        },
        generics: t.generics.clean(),
        fn_style: style,
    }
}

fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct {
    use syntax::parse::token::special_idents::unnamed_field;

    let t = ty::lookup_item_type(tcx, did);
    let fields = ty::lookup_struct_fields(tcx, did);

    clean::Struct {
        struct_type: match fields.as_slice() {
            [] => doctree::Unit,
            [ref f] if f.name == unnamed_field.name => doctree::Newtype,
            [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple,
            _ => doctree::Plain,
        },
        generics: t.generics.clean(),
        fields: fields.iter().map(|f| f.clean()).collect(),
        fields_stripped: false,
    }
}

fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
    let t = ty::lookup_item_type(tcx, did);
    match ty::get(t.ty).sty {
        ty::ty_enum(edid, _) => {
            return clean::EnumItem(clean::Enum {
                generics: t.generics.clean(),
                variants_stripped: false,
                variants: ty::enum_variants(tcx, edid).clean(),
            })
        }
        _ => {}
    }

    clean::TypedefItem(clean::Typedef {
        type_: t.ty.clean(),
        generics: t.generics.clean(),
    })
}

fn build_impls(cx: &core::DocContext,
               tcx: &ty::ctxt,
               did: ast::DefId) -> Vec<clean::Item> {
    ty::populate_implementations_for_type_if_necessary(tcx, did);
    let mut impls = Vec::new();

    match tcx.inherent_impls.borrow().find(&did) {
        None => {}
        Some(i) => {
            impls.extend(i.borrow().iter().map(|&did| { build_impl(cx, tcx, did) }));
        }
    }

    // If this is the first time we've inlined something from this crate, then
    // we inline *all* impls from the crate into this crate. Note that there's
    // currently no way for us to filter this based on type, and we likely need
    // many impls for a variety of reasons.
    //
    // Primarily, the impls will be used to populate the documentation for this
    // type being inlined, but impls can also be used when generating
    // documentation for primitives (no way to find those specifically).
    if cx.populated_crate_impls.borrow_mut().insert(did.krate) {
        csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
                                              did.krate,
                                              |def, _, _| {
            populate_impls(cx, tcx, def, &mut impls)
        });

        fn populate_impls(cx: &core::DocContext,
                          tcx: &ty::ctxt,
                          def: decoder::DefLike,
                          impls: &mut Vec<Option<clean::Item>>) {
            match def {
                decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)),
                decoder::DlDef(ast::DefMod(did)) => {
                    csearch::each_child_of_item(&tcx.sess.cstore,
                                                did,
                                                |def, _, _| {
                        populate_impls(cx, tcx, def, impls)
                    })
                }
                _ => {}
            }
        }
    }

    impls.move_iter().filter_map(|a| a).collect()
}

fn build_impl(cx: &core::DocContext,
              tcx: &ty::ctxt,
              did: ast::DefId) -> Option<clean::Item> {
    if !cx.inlined.borrow_mut().get_mut_ref().insert(did) {
        return None
    }

    let associated_trait = csearch::get_impl_trait(tcx, did);
    let attrs = load_attrs(tcx, did);
    let ty = ty::lookup_item_type(tcx, did);
    let methods = csearch::get_impl_methods(&tcx.sess.cstore,
                                            did).iter().filter_map(|did| {
        let method = ty::method(tcx, *did);
        if method.vis != ast::Public && associated_trait.is_none() {
            return None
        }
        let mut item = ty::method(tcx, *did).clean();
        item.inner = match item.inner.clone() {
            clean::TyMethodItem(clean::TyMethod {
                fn_style, decl, self_, generics
            }) => {
                clean::MethodItem(clean::Method {
                    fn_style: fn_style,
                    decl: decl,
                    self_: self_,
                    generics: generics,
                })
            }
            _ => fail!("not a tymethod"),
        };
        Some(item)
    }).collect();
    Some(clean::Item {
        inner: clean::ImplItem(clean::Impl {
            derived: clean::detect_derived(attrs.as_slice()),
            trait_: associated_trait.clean().map(|bound| {
                match bound {
                    clean::TraitBound(ty) => ty,
                    clean::RegionBound => unreachable!(),
                }
            }),
            for_: ty.ty.clean(),
            generics: ty.generics.clean(),
            methods: methods,
        }),
        source: clean::Span::empty(),
        name: None,
        attrs: attrs,
        visibility: Some(ast::Inherited),
        def_id: did,
    })
}

fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
                did: ast::DefId) -> clean::Module {
    let mut items = Vec::new();

    // FIXME: this doesn't handle reexports inside the module itself.
    //        Should they be handled?
    csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| {
        if vis != ast::Public { return }
        match def {
            decoder::DlDef(def) => {
                match try_inline_def(cx, tcx, def) {
                    Some(i) => items.extend(i.move_iter()),
                    None => {}
                }
            }
            // All impls were inlined above
            decoder::DlImpl(..) => {}
            decoder::DlField => fail!("unimplemented field"),
        }
    });

    clean::Module {
        items: items,
        is_crate: false,
    }
}
<|endoftext|>


<commit_before>//! Experimental extensions to `std` for Unix platforms.
//!
//! Provides access to platform-level information on Unix platforms, and
//! exposes Unix-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//!     let f = File::create("foo.txt").unwrap();
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native unix bindings
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]
#![allow(missing_docs)]

pub mod io;
pub mod ffi;
pub mod fs;
pub mod process;
pub mod raw;
pub mod thread;
pub mod net;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::DirEntryExt;
    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
    pub use super::fs::FileExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::thread::JoinHandleExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::process::{CommandExt, ExitStatusExt};
}
<commit_msg>Rollup merge of #58382 - euclio:unix-ext, r=dtolnay<commit_after>//! Platform-specific extensions to `std` for Unix platforms.
//!
//! Provides access to platform-level information on Unix platforms, and
//! exposes Unix-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//!     let f = File::create("foo.txt").unwrap();
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native unix bindings
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]
#![allow(missing_docs)]

pub mod io;
pub mod ffi;
pub mod fs;
pub mod process;
pub mod raw;
pub mod thread;
pub mod net;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::DirEntryExt;
    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
    pub use super::fs::FileExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::thread::JoinHandleExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::process::{CommandExt, ExitStatusExt};
}
<|endoftext|>


<commit_before>use super::run_with_splits;
use comparison::median_segments::{MedianSegments, NAME};
use {Run, Segment, TimeSpan, Timer};

#[test]
fn test() {
    let s = TimeSpan::from_seconds;

    let mut run = Run::new();

    run.push_segment(Segment::new("First"));

    run.comparison_generators_mut().clear();
    run.comparison_generators_mut()
        .push(Box::new(MedianSegments));

    let mut timer = Timer::new(run).unwrap();

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, None);
    }

    run_with_splits(&mut timer, &[0.0]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(0.0)));
    }

    run_with_splits(&mut timer, &[1.0]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(1.0)));
    }

    run_with_splits(&mut timer, &[0.6]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(0.6)));
    }

    run_with_splits(&mut timer, &[0.3]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(0.3)));
    }

    run_with_splits(&mut timer, &[1.0]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(0.6)));
    }
}
<commit_msg>Fix i586 precision issue in median test<commit_after>use super::run_with_splits;
use comparison::median_segments::{MedianSegments, NAME};
use {Run, Segment, TimeSpan, Timer};

#[test]
fn test() {
    let s = TimeSpan::from_seconds;

    let mut run = Run::new();

    run.push_segment(Segment::new("First"));

    run.comparison_generators_mut().clear();
    run.comparison_generators_mut()
        .push(Box::new(MedianSegments));

    let mut timer = Timer::new(run).unwrap();

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, None);
    }

    run_with_splits(&mut timer, &[0.0]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(0.0)));
    }

    run_with_splits(&mut timer, &[1.0]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(1.0)));
    }

    run_with_splits(&mut timer, &[0.6]);

    {
        let run = timer.run();
        assert!(run.segment(0).comparison(NAME).game_time < Some(s(0.61)));
        assert!(run.segment(0).comparison(NAME).game_time > Some(s(0.59)));
    }

    run_with_splits(&mut timer, &[0.3]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(0.3)));
    }

    run_with_splits(&mut timer, &[1.0]);

    {
        let run = timer.run();
        assert_eq!(run.segment(0).comparison(NAME).game_time, Some(s(0.6)));
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword(
    "visibility",
    "visible hidden collapse",
    engines="gecko servo-2013 servo-2020",
    gecko_ffi_name="mVisible",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-box/#propdef-visibility",
    gecko_enum_prefix="StyleVisibility",
)}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword(
    "writing-mode",
    "horizontal-tb vertical-rl vertical-lr",
    engines="gecko servo-2013 servo-2020",
    extra_gecko_values="sideways-rl sideways-lr",
    gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                         rl=horizontal-tb rl-tb=horizontal-tb \
                         tb=vertical-rl   tb-rl=vertical-rl",
    servo_2013_pref="layout.writing-mode.enabled",
    servo_2020_pref="layout.writing-mode.enabled",
    animation_value_type="none",
    spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "direction",
    "ltr rtl",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="none",
    spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
    gecko_enum_prefix="StyleDirection",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "text-orientation",
    "mixed upright sideways",
    engines="gecko",
    gecko_aliases="sideways-right=sideways",
    gecko_enum_prefix="StyleTextOrientation",
    animation_value_type="none",
    spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation",
)}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword(
    "color-adjust",
    "economy exact",
    engines="gecko",
    gecko_enum_prefix="StyleColorAdjust",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-color/#propdef-color-adjust",
)}

// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword(
    "image-rendering",
    "auto crisp-edges",
    engines="gecko servo-2013 servo-2020",
    extra_gecko_values="optimizespeed optimizequality",
    extra_servo_2013_values="pixelated",
    extra_servo_2020_values="pixelated",
    gecko_aliases="-moz-crisp-edges=crisp-edges",
    gecko_enum_prefix="StyleImageRendering",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-images/#propdef-image-rendering",
)}

${helpers.single_keyword(
    "image-orientation",
    "none from-image",
    gecko_pref_controlled_initial_value="layout.css.image-orientation.initial-from-image=from-image",
    engines="gecko",
    gecko_enum_prefix="StyleImageOrientation",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation",
)}
<commit_msg>style: Convert writing-modes #defines to an enum class.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword(
    "visibility",
    "visible hidden collapse",
    engines="gecko servo-2013 servo-2020",
    gecko_ffi_name="mVisible",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-box/#propdef-visibility",
    gecko_enum_prefix="StyleVisibility",
)}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword(
    "writing-mode",
    "horizontal-tb vertical-rl vertical-lr",
    engines="gecko servo-2013 servo-2020",
    extra_gecko_values="sideways-rl sideways-lr",
    gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                         rl=horizontal-tb rl-tb=horizontal-tb \
                         tb=vertical-rl   tb-rl=vertical-rl",
    servo_2013_pref="layout.writing-mode.enabled",
    servo_2020_pref="layout.writing-mode.enabled",
    animation_value_type="none",
    spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode",
    gecko_enum_prefix="StyleWritingModeProperty",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "direction",
    "ltr rtl",
    engines="gecko servo-2013 servo-2020",
    servo_2020_pref="layout.2020.unimplemented",
    animation_value_type="none",
    spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
    gecko_enum_prefix="StyleDirection",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "text-orientation",
    "mixed upright sideways",
    engines="gecko",
    gecko_aliases="sideways-right=sideways",
    gecko_enum_prefix="StyleTextOrientation",
    animation_value_type="none",
    spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation",
)}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword(
    "color-adjust",
    "economy exact",
    engines="gecko",
    gecko_enum_prefix="StyleColorAdjust",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-color/#propdef-color-adjust",
)}

// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword(
    "image-rendering",
    "auto crisp-edges",
    engines="gecko servo-2013 servo-2020",
    extra_gecko_values="optimizespeed optimizequality",
    extra_servo_2013_values="pixelated",
    extra_servo_2020_values="pixelated",
    gecko_aliases="-moz-crisp-edges=crisp-edges",
    gecko_enum_prefix="StyleImageRendering",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-images/#propdef-image-rendering",
)}

${helpers.single_keyword(
    "image-orientation",
    "none from-image",
    gecko_pref_controlled_initial_value="layout.css.image-orientation.initial-from-image=from-image",
    engines="gecko",
    gecko_enum_prefix="StyleImageOrientation",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation",
)}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::OsString;
use std::io;
use std::ops::Deref;
use std::os::unix::io::{IntoRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::sync::Arc;

use nix::fcntl;

use crate::{EventQueue, Proxy};

use crate::imp::DisplayInner;

#[cfg(feature = "use_system_lib")]
use wayland_sys::client::wl_display;

/// Enum representing the possible reasons why connecting to the wayland server failed
#[derive(Debug)]
pub enum ConnectError {
    /// The library was compiled with the `dlopen` feature, and the `libwayland-client.so`
    /// library could not be found at runtime
    NoWaylandLib,
    /// The `XDG_RUNTIME_DIR` variable is not set while it should be
    XdgRuntimeDirNotSet,
    /// Any needed library was found, but the listening socket of the server was not.
    ///
    /// Most of the time, this means that the program was not started from a wayland session.
    NoCompositorListening,
    /// The provided socket name is invalid
    InvalidName,
    /// The FD provided in `WAYLAND_SOCKET` was invalid
    InvalidFd,
}

impl ::std::error::Error for ConnectError {}

impl ::std::fmt::Display for ConnectError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        match *self {
            ConnectError::NoWaylandLib => f.write_str("Could not find libwayland-client.so."),
            ConnectError::XdgRuntimeDirNotSet => f.write_str("XDG_RUNTIME_DIR is not set."),
            ConnectError::NoCompositorListening => {
                f.write_str("Could not find a listening wayland compositor.")
            }
            ConnectError::InvalidName => f.write_str("The wayland socket name is invalid."),
            ConnectError::InvalidFd => f.write_str("The FD provided in WAYLAND_SOCKET is invalid."),
        }
    }
}

/// A protocol error
///
/// This kind of error is generated by the server if your client didn't respect
/// the protocol, after which the server will kill your connection.
///
/// If the dispatching methods of `EventQueues` start to fail, you may want to
/// check `Display::protocol_error()` to see if a protocol error was generated.
#[derive(Clone, Debug)]
pub struct ProtocolError {
    /// The error code associated with the error
    ///
    /// It should be interpreted as an instance of the `Error` enum of the
    /// associated interface.
    pub code: u32,
    /// The id of the object that caused the error
    pub object_id: u32,
    /// The interface of the object that caused the error
    pub object_interface: &'static str,
    /// The message sent by the server describing the error
    pub message: String,
}

impl ::std::error::Error for ProtocolError {
    fn description(&self) -> &str {
        "Wayland protocol error"
    }
}

impl ::std::fmt::Display for ProtocolError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(
            f,
            "Protocol error {} on object {}@{}: {}",
            self.code, self.object_interface, self.object_id, self.message
        )
    }
}

/// A connection to a wayland server
///
/// This object both represent the connection to the server and contains the
/// primary `WlDisplay` wayland object. As such, it must be kept alive as long
/// as you are connected. You can access the contained `WlDisplay` via `Deref`
/// to create all the objects you need.
///
/// **Safety note:** If you activate the `use_system_lib` cargo feature and provide pointers
/// to wayland objects to other libraries, you **must** ensure that these libraries clean up
/// their state before the last clone of this `Display` is dropped, otherwise these libraries
/// will access freed memory when doing their cleanup.
#[derive(Clone)]
pub struct Display {
    pub(crate) inner: Arc<DisplayInner>,
}

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

impl Display {
    /// Attempt to connect to a wayland server using the contents of the environment variables
    ///
    /// First of all, if the `WAYLAND_SOCKET` environment variable is set, it'll try to interpret
    /// it as a FD number to use.
    ///
    /// Otherwise, it will try to connect to the socket name defined in the `WAYLAND_DISPLAY`
    /// environment variable, and error if it is not set.
    ///
    /// This requires the `XDG_RUNTIME_DIR` variable to be properly set.
    pub fn connect_to_env() -> Result<Display, ConnectError> {
        if let Ok(txt) = env::var("WAYLAND_SOCKET") {
            // We should connect to the provided WAYLAND_SOCKET
            let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
            // remove the variable so any child processes don't see it
            env::remove_var("WAYLAND_SOCKET");
            // set the CLOEXEC flag on this FD
            let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD);
            let result = flags
                .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
                .and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f)));
            match result {
                Ok(_) => {
                    // setting the O_CLOEXEC worked
                    unsafe { Display::from_fd(fd) }
                }
                Err(_) => {
                    // something went wrong in F_GETFD or F_SETFD
                    let _ = ::nix::unistd::close(fd);
                    Err(ConnectError::InvalidFd)
                }
            }
        } else {
            let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
                .map(Into::<PathBuf>::into)
                .ok_or(ConnectError::XdgRuntimeDirNotSet)?;
            socket_path
                .push(env::var_os("WAYLAND_DISPLAY").ok_or(ConnectError::NoCompositorListening)?);

            let socket = UnixStream::connect(socket_path)
                .map_err(|_| ConnectError::NoCompositorListening)?;
            unsafe { Display::from_fd(socket.into_raw_fd()) }
        }
    }

    /// Attempt to connect to a wayland server socket with given name
    ///
    /// On success, you are given the `Display` object as well as the main `EventQueue` hosting
    /// the `WlDisplay` wayland object.
    ///
    /// This requires the `XDG_RUNTIME_DIR` variable to be properly set.
    pub fn connect_to_name<S: Into<OsString>>(name: S) -> Result<Display, ConnectError> {
        let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
            .map(Into::<PathBuf>::into)
            .ok_or(ConnectError::XdgRuntimeDirNotSet)?;
        socket_path.push(name.into());

        let socket =
            UnixStream::connect(socket_path).map_err(|_| ConnectError::NoCompositorListening)?;
        unsafe { Display::from_fd(socket.into_raw_fd()) }
    }

    /// Attempt to use an already connected unix socket on given FD to start a wayland connection
    ///
    /// On success, you are given the `Display` object.
    ///
    /// Will take ownership of the FD.
    ///
    /// # Safety
    ///
    /// The file descriptor must be associated to a connected unix socket.
    pub unsafe fn from_fd(fd: RawFd) -> Result<Display, ConnectError> {
        Ok(Display { inner: DisplayInner::from_fd(fd)? })
    }

    /// Non-blocking write to the server
    ///
    /// Outgoing messages to the server are buffered by the library for efficiency. This method
    /// flushes the internal buffer to the server socket.
    ///
    /// Will write as many pending requests as possible to the server socket. Never blocks: if not all
    /// requests could be written, will return an io error `WouldBlock`.
    ///
    /// This function is identical to `EventQueue::flush`
    pub fn flush(&self) -> io::Result<()> {
        self.inner.flush()
    }

    /// Create a new event queue associated with this wayland connection
    pub fn create_event_queue(&self) -> EventQueue {
        let evq_inner = DisplayInner::create_event_queue(&self.inner);
        EventQueue::new(evq_inner, self.clone())
    }

    /// Retrieve the last protocol error if any occured
    ///
    /// If your client does not respect some part of a protocol it is using, the server
    /// will send a special "protocol error" event and kill your connection. This method
    /// allows you to retrieve the contents of this event if it occured.
    ///
    /// If the dispatch methods of the `EventQueue` return an error, this is an indication
    /// that a protocol error may have occured. Such errors are not recoverable, but this
    /// method allows you to gracefully display them to the user, along with indications for
    /// submitting a bug-report for example.
    pub fn protocol_error(&self) -> Option<ProtocolError> {
        self.inner.protocol_error()
    }

    /// Retrieve the file descriptor associated with the wayland socket
    ///
    /// This FD should only be used to integrate into a polling mechanism, and should
    /// never be directly read from or written to.
    pub fn get_connection_fd(&self) -> ::std::os::unix::io::RawFd {
        self.inner.get_connection_fd()
    }

    #[cfg(feature = "use_system_lib")]
    /// Create a Display and from an external display
    ///
    /// This allows you to interface with an already-existing wayland connection,
    /// for example provided by a GUI toolkit.
    ///
    /// Note that if you need to retrieve the actual `wl_display` pointer back (rather than
    /// its wrapper), you must use the `get_display_ptr()` method.
    ///
    /// # Safety
    ///
    /// The provided pointer must point to a valid `wl_display` from `libwayland-client`
    pub unsafe fn from_external_display(display_ptr: *mut wl_display) -> Display {
        Display { inner: DisplayInner::from_external(display_ptr) }
    }

    #[cfg(feature = "use_system_lib")]
    /// Retrieve the `wl_display` pointer
    ///
    /// If this `Display` was created from an external `wl_display`, its `c_ptr()` method will
    /// return a wrapper to the actual display. While this is perfectly good as a `wl_proxy`
    /// pointer, to send requests, this is not the actual `wl_display` and cannot be used as such.
    ///
    /// This method will give you the `wl_display`.
    pub fn get_display_ptr(&self) -> *mut wl_display {
        self.inner.ptr()
    }
}

impl Deref for Display {
    type Target = Proxy<crate::protocol::wl_display::WlDisplay>;
    fn deref(&self) -> &Proxy<crate::protocol::wl_display::WlDisplay> {
        self.inner.get_proxy()
    }
}
<commit_msg>Remove reference to non-existent function<commit_after>use std::env;
use std::ffi::OsString;
use std::io;
use std::ops::Deref;
use std::os::unix::io::{IntoRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::sync::Arc;

use nix::fcntl;

use crate::{EventQueue, Proxy};

use crate::imp::DisplayInner;

#[cfg(feature = "use_system_lib")]
use wayland_sys::client::wl_display;

/// Enum representing the possible reasons why connecting to the wayland server failed
#[derive(Debug)]
pub enum ConnectError {
    /// The library was compiled with the `dlopen` feature, and the `libwayland-client.so`
    /// library could not be found at runtime
    NoWaylandLib,
    /// The `XDG_RUNTIME_DIR` variable is not set while it should be
    XdgRuntimeDirNotSet,
    /// Any needed library was found, but the listening socket of the server was not.
    ///
    /// Most of the time, this means that the program was not started from a wayland session.
    NoCompositorListening,
    /// The provided socket name is invalid
    InvalidName,
    /// The FD provided in `WAYLAND_SOCKET` was invalid
    InvalidFd,
}

impl ::std::error::Error for ConnectError {}

impl ::std::fmt::Display for ConnectError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        match *self {
            ConnectError::NoWaylandLib => f.write_str("Could not find libwayland-client.so."),
            ConnectError::XdgRuntimeDirNotSet => f.write_str("XDG_RUNTIME_DIR is not set."),
            ConnectError::NoCompositorListening => {
                f.write_str("Could not find a listening wayland compositor.")
            }
            ConnectError::InvalidName => f.write_str("The wayland socket name is invalid."),
            ConnectError::InvalidFd => f.write_str("The FD provided in WAYLAND_SOCKET is invalid."),
        }
    }
}

/// A protocol error
///
/// This kind of error is generated by the server if your client didn't respect
/// the protocol, after which the server will kill your connection.
///
/// If the dispatching methods of `EventQueues` start to fail, you may want to
/// check `Display::protocol_error()` to see if a protocol error was generated.
#[derive(Clone, Debug)]
pub struct ProtocolError {
    /// The error code associated with the error
    ///
    /// It should be interpreted as an instance of the `Error` enum of the
    /// associated interface.
    pub code: u32,
    /// The id of the object that caused the error
    pub object_id: u32,
    /// The interface of the object that caused the error
    pub object_interface: &'static str,
    /// The message sent by the server describing the error
    pub message: String,
}

impl ::std::error::Error for ProtocolError {
    fn description(&self) -> &str {
        "Wayland protocol error"
    }
}

impl ::std::fmt::Display for ProtocolError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(
            f,
            "Protocol error {} on object {}@{}: {}",
            self.code, self.object_interface, self.object_id, self.message
        )
    }
}

/// A connection to a wayland server
///
/// This object both represent the connection to the server and contains the
/// primary `WlDisplay` wayland object. As such, it must be kept alive as long
/// as you are connected. You can access the contained `WlDisplay` via `Deref`
/// to create all the objects you need.
///
/// **Safety note:** If you activate the `use_system_lib` cargo feature and provide pointers
/// to wayland objects to other libraries, you **must** ensure that these libraries clean up
/// their state before the last clone of this `Display` is dropped, otherwise these libraries
/// will access freed memory when doing their cleanup.
#[derive(Clone)]
pub struct Display {
    pub(crate) inner: Arc<DisplayInner>,
}

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

impl Display {
    /// Attempt to connect to a wayland server using the contents of the environment variables
    ///
    /// First of all, if the `WAYLAND_SOCKET` environment variable is set, it'll try to interpret
    /// it as a FD number to use.
    ///
    /// Otherwise, it will try to connect to the socket name defined in the `WAYLAND_DISPLAY`
    /// environment variable, and error if it is not set.
    ///
    /// This requires the `XDG_RUNTIME_DIR` variable to be properly set.
    pub fn connect_to_env() -> Result<Display, ConnectError> {
        if let Ok(txt) = env::var("WAYLAND_SOCKET") {
            // We should connect to the provided WAYLAND_SOCKET
            let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
            // remove the variable so any child processes don't see it
            env::remove_var("WAYLAND_SOCKET");
            // set the CLOEXEC flag on this FD
            let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD);
            let result = flags
                .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
                .and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f)));
            match result {
                Ok(_) => {
                    // setting the O_CLOEXEC worked
                    unsafe { Display::from_fd(fd) }
                }
                Err(_) => {
                    // something went wrong in F_GETFD or F_SETFD
                    let _ = ::nix::unistd::close(fd);
                    Err(ConnectError::InvalidFd)
                }
            }
        } else {
            let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
                .map(Into::<PathBuf>::into)
                .ok_or(ConnectError::XdgRuntimeDirNotSet)?;
            socket_path
                .push(env::var_os("WAYLAND_DISPLAY").ok_or(ConnectError::NoCompositorListening)?);

            let socket = UnixStream::connect(socket_path)
                .map_err(|_| ConnectError::NoCompositorListening)?;
            unsafe { Display::from_fd(socket.into_raw_fd()) }
        }
    }

    /// Attempt to connect to a wayland server socket with given name
    ///
    /// On success, you are given the `Display` object as well as the main `EventQueue` hosting
    /// the `WlDisplay` wayland object.
    ///
    /// This requires the `XDG_RUNTIME_DIR` variable to be properly set.
    pub fn connect_to_name<S: Into<OsString>>(name: S) -> Result<Display, ConnectError> {
        let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
            .map(Into::<PathBuf>::into)
            .ok_or(ConnectError::XdgRuntimeDirNotSet)?;
        socket_path.push(name.into());

        let socket =
            UnixStream::connect(socket_path).map_err(|_| ConnectError::NoCompositorListening)?;
        unsafe { Display::from_fd(socket.into_raw_fd()) }
    }

    /// Attempt to use an already connected unix socket on given FD to start a wayland connection
    ///
    /// On success, you are given the `Display` object.
    ///
    /// Will take ownership of the FD.
    ///
    /// # Safety
    ///
    /// The file descriptor must be associated to a connected unix socket.
    pub unsafe fn from_fd(fd: RawFd) -> Result<Display, ConnectError> {
        Ok(Display { inner: DisplayInner::from_fd(fd)? })
    }

    /// Non-blocking write to the server
    ///
    /// Outgoing messages to the server are buffered by the library for efficiency. This method
    /// flushes the internal buffer to the server socket.
    ///
    /// Will write as many pending requests as possible to the server socket. Never blocks: if not all
    /// requests could be written, will return an io error `WouldBlock`.
    pub fn flush(&self) -> io::Result<()> {
        self.inner.flush()
    }

    /// Create a new event queue associated with this wayland connection
    pub fn create_event_queue(&self) -> EventQueue {
        let evq_inner = DisplayInner::create_event_queue(&self.inner);
        EventQueue::new(evq_inner, self.clone())
    }

    /// Retrieve the last protocol error if any occured
    ///
    /// If your client does not respect some part of a protocol it is using, the server
    /// will send a special "protocol error" event and kill your connection. This method
    /// allows you to retrieve the contents of this event if it occured.
    ///
    /// If the dispatch methods of the `EventQueue` return an error, this is an indication
    /// that a protocol error may have occured. Such errors are not recoverable, but this
    /// method allows you to gracefully display them to the user, along with indications for
    /// submitting a bug-report for example.
    pub fn protocol_error(&self) -> Option<ProtocolError> {
        self.inner.protocol_error()
    }

    /// Retrieve the file descriptor associated with the wayland socket
    ///
    /// This FD should only be used to integrate into a polling mechanism, and should
    /// never be directly read from or written to.
    pub fn get_connection_fd(&self) -> ::std::os::unix::io::RawFd {
        self.inner.get_connection_fd()
    }

    #[cfg(feature = "use_system_lib")]
    /// Create a Display and from an external display
    ///
    /// This allows you to interface with an already-existing wayland connection,
    /// for example provided by a GUI toolkit.
    ///
    /// Note that if you need to retrieve the actual `wl_display` pointer back (rather than
    /// its wrapper), you must use the `get_display_ptr()` method.
    ///
    /// # Safety
    ///
    /// The provided pointer must point to a valid `wl_display` from `libwayland-client`
    pub unsafe fn from_external_display(display_ptr: *mut wl_display) -> Display {
        Display { inner: DisplayInner::from_external(display_ptr) }
    }

    #[cfg(feature = "use_system_lib")]
    /// Retrieve the `wl_display` pointer
    ///
    /// If this `Display` was created from an external `wl_display`, its `c_ptr()` method will
    /// return a wrapper to the actual display. While this is perfectly good as a `wl_proxy`
    /// pointer, to send requests, this is not the actual `wl_display` and cannot be used as such.
    ///
    /// This method will give you the `wl_display`.
    pub fn get_display_ptr(&self) -> *mut wl_display {
        self.inner.ptr()
    }
}

impl Deref for Display {
    type Target = Proxy<crate::protocol::wl_display::WlDisplay>;
    fn deref(&self) -> &Proxy<crate::protocol::wl_display::WlDisplay> {
        self.inner.get_proxy()
    }
}
<|endoftext|>


<commit_before>pub(crate) 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::{PgTransactionStatus, RawConnection};
use self::result::PgResult;
use self::stmt::Statement;
use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
use crate::connection::*;
use crate::expression::QueryMetadata;
use crate::pg::metadata_lookup::{GetPgMetadataCache, PgMetadataCache};
use crate::pg::{Pg, TransactionBuilder};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::*;
use crate::result::ConnectionError::CouldntSetupConfiguration;
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,
    transaction_state: AnsiTransactionManager,
    statement_cache: StatementCache<Pg, Statement>,
    metadata_cache: PgMetadataCache,
}

unsafe impl Send for PgConnection {}

impl SimpleConnection for PgConnection {
    fn batch_execute(&mut 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<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Pg> for PgConnection {
    type Cursor = Cursor;
    type Row = self::row::PgRow;
}

impl CommitErrorProcessor for PgConnection {
    fn process_commit_error(&self, transaction_depth: i32, error: Error) -> CommitErrorOutcome {
        if matches!(
            error,
            Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
        ) {
            return CommitErrorOutcome::Throw(error);
        }
        if transaction_depth <= 1 {
            match error {
                Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _) => {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction
                | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
                | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
                | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                | Error::DeserializationError(_)
                | Error::InvalidCString(_)
                | Error::NotFound
                | Error::QueryBuilderError(_)
                | Error::RollbackError(_)
                | Error::NotInTransaction
                | Error::RollbackTransaction
                | Error::SerializationError(_)
                | Error::BrokenTransaction => CommitErrorOutcome::Throw(error),
            }
        } else {
            let transaction_status = self.raw_connection.transaction_status();
            match error {
                Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                    if transaction_status == PgTransactionStatus::InError =>
                {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction
                | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
                | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)
                | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
                | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                | Error::DeserializationError(_)
                | Error::InvalidCString(_)
                | Error::NotFound
                | Error::QueryBuilderError(_)
                | Error::RollbackError(_)
                | Error::NotInTransaction
                | Error::RollbackTransaction
                | Error::SerializationError(_)
                | Error::BrokenTransaction => CommitErrorOutcome::Throw(error),
            }
        }
    }
}

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 mut conn = PgConnection {
                raw_connection: raw_conn,
                transaction_state: AnsiTransactionManager::default(),
                statement_cache: StatementCache::new(),
                metadata_cache: PgMetadataCache::new(),
            };
            conn.set_config_options()
                .map_err(CouldntSetupConfiguration)?;
            Ok(conn)
        })
    }

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

    #[doc(hidden)]
    fn load<'conn, 'query, T>(
        &'conn mut self,
        source: T,
    ) -> QueryResult<<Self as ConnectionGatWorkaround<'conn, 'query, Pg>>::Cursor>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId + 'query,
        Self::Backend: QueryMetadata<T::SqlType>,
    {
        self.with_prepared_query(&source.as_query(), |stmt, params, conn| {
            let result = stmt.execute(conn, &params)?;
            let cursor = Cursor::new(result);

            Ok(cursor)
        })
    }

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

    fn transaction_state(&mut self) -> &mut AnsiTransactionManager
    where
        Self: Sized,
    {
        &mut self.transaction_state
    }
}

impl GetPgMetadataCache for PgConnection {
    fn get_metadata_cache(&mut self) -> &mut PgMetadataCache {
        &mut self.metadata_cache
    }
}

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

    fn with_prepared_query<'conn, T: QueryFragment<Pg> + QueryId, R>(
        &'conn mut self,
        source: &'_ T,
        f: impl FnOnce(
            MaybeCached<'_, Statement>,
            Vec<Option<Vec<u8>>>,
            &'conn mut RawConnection,
        ) -> QueryResult<R>,
    ) -> QueryResult<R> {
        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 cache = &mut self.statement_cache;
        let raw_conn = &mut self.raw_connection;
        let query = 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(raw_conn, sql, query_name.as_deref(), &metadata)
        });

        f(query?, binds, raw_conn)
    }

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

    fn set_config_options(&mut 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(())
    }
}

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

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

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

    #[test]
    fn malformed_sql_query() {
        let connection = &mut connection();
        let query =
            crate::sql_query("SELECT not_existent FROM also_not_there;").execute(connection);

        if let Err(err) = query {
            if let DatabaseError(_, string) = err {
                assert_eq!(Some(26), string.statement_position());
            } else {
                unreachable!();
            }
        } else {
            unreachable!();
        }
    }

    #[test]
    fn prepared_statements_are_cached() {
        let connection = &mut 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 = &mut 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 = &mut 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 = &mut 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 = &mut connection();
        let query = crate::select(sql::<Integer>("1"));

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

    table! {
        users {
            id -> Integer,
            name -> Text,
        }
    }

    #[test]
    fn inserts_from_select_are_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let query = users::table.filter(users::id.eq(42));
        let insert = query
            .insert_into(users::table)
            .into_columns((users::id, users::name));
        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(1, connection.statement_cache.len());

        let query = users::table.filter(users::id.eq(42)).into_boxed();
        let insert = query
            .insert_into(users::table)
            .into_columns((users::id, users::name));
        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(2, connection.statement_cache.len());
    }

    #[test]
    fn single_inserts_are_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let insert =
            crate::insert_into(users::table).values((users::id.eq(42), users::name.eq("Foo")));

        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(1, connection.statement_cache.len());
    }

    #[test]
    fn dynamic_batch_inserts_are_not_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let insert = crate::insert_into(users::table)
            .values(vec![(users::id.eq(42), users::name.eq("Foo"))]);

        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(0, connection.statement_cache.len());
    }

    #[test]
    fn static_batch_inserts_are_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let insert =
            crate::insert_into(users::table).values([(users::id.eq(42), users::name.eq("Foo"))]);

        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(1, connection.statement_cache.len());
    }

    #[test]
    fn queries_containing_in_with_vec_are_cached() {
        let connection = &mut connection();
        let one_as_expr = 1.into_sql::<Integer>();
        let query = crate::select(one_as_expr.eq_any(vec![1, 2, 3]));

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

    fn connection() -> PgConnection {
        crate::test_helpers::pg_connection_no_transaction()
    }
}
<commit_msg>Mark transaction manager as broken when a Postgres transaction returns PQTRANS_UNKNOWN<commit_after>pub(crate) 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::{PgTransactionStatus, RawConnection};
use self::result::PgResult;
use self::stmt::Statement;
use crate::connection::commit_error_processor::{CommitErrorOutcome, CommitErrorProcessor};
use crate::connection::*;
use crate::expression::QueryMetadata;
use crate::pg::metadata_lookup::{GetPgMetadataCache, PgMetadataCache};
use crate::pg::{Pg, TransactionBuilder};
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::*;
use crate::result::ConnectionError::CouldntSetupConfiguration;
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,
    transaction_state: AnsiTransactionManager,
    statement_cache: StatementCache<Pg, Statement>,
    metadata_cache: PgMetadataCache,
}

unsafe impl Send for PgConnection {}

impl SimpleConnection for PgConnection {
    fn batch_execute(&mut 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<'conn, 'query> ConnectionGatWorkaround<'conn, 'query, Pg> for PgConnection {
    type Cursor = Cursor;
    type Row = self::row::PgRow;
}

impl CommitErrorProcessor for PgConnection {
    fn process_commit_error(&self, transaction_depth: i32, error: Error) -> CommitErrorOutcome {
        let transaction_status = self.raw_connection.transaction_status();
        if transaction_status == PgTransactionStatus::Unknown {
            return CommitErrorOutcome::ThrowAndMarkManagerAsBroken(error);
        }
        if matches!(
            error,
            Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
        ) {
            return CommitErrorOutcome::Throw(error);
        }
        if transaction_depth <= 1 {
            match error {
                Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _) => {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction
                | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
                | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
                | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                | Error::DeserializationError(_)
                | Error::InvalidCString(_)
                | Error::NotFound
                | Error::QueryBuilderError(_)
                | Error::RollbackError(_)
                | Error::NotInTransaction
                | Error::RollbackTransaction
                | Error::SerializationError(_)
                | Error::BrokenTransaction => CommitErrorOutcome::Throw(error),
            }
        } else {
            match error {
                Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                    if transaction_status == PgTransactionStatus::InError =>
                {
                    CommitErrorOutcome::RollbackAndThrow(error)
                }
                Error::AlreadyInTransaction
                | Error::DatabaseError(DatabaseErrorKind::CheckViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ClosedConnection, _)
                | Error::DatabaseError(DatabaseErrorKind::ForeignKeyViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::NotNullViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::ReadOnlyTransaction, _)
                | Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)
                | Error::DatabaseError(DatabaseErrorKind::UnableToSendCommand, _)
                | Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)
                | Error::DatabaseError(DatabaseErrorKind::Unknown, _)
                | Error::DeserializationError(_)
                | Error::InvalidCString(_)
                | Error::NotFound
                | Error::QueryBuilderError(_)
                | Error::RollbackError(_)
                | Error::NotInTransaction
                | Error::RollbackTransaction
                | Error::SerializationError(_)
                | Error::BrokenTransaction => CommitErrorOutcome::Throw(error),
            }
        }
    }
}

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 mut conn = PgConnection {
                raw_connection: raw_conn,
                transaction_state: AnsiTransactionManager::default(),
                statement_cache: StatementCache::new(),
                metadata_cache: PgMetadataCache::new(),
            };
            conn.set_config_options()
                .map_err(CouldntSetupConfiguration)?;
            Ok(conn)
        })
    }

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

    #[doc(hidden)]
    fn load<'conn, 'query, T>(
        &'conn mut self,
        source: T,
    ) -> QueryResult<<Self as ConnectionGatWorkaround<'conn, 'query, Pg>>::Cursor>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId + 'query,
        Self::Backend: QueryMetadata<T::SqlType>,
    {
        self.with_prepared_query(&source.as_query(), |stmt, params, conn| {
            let result = stmt.execute(conn, &params)?;
            let cursor = Cursor::new(result);

            Ok(cursor)
        })
    }

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

    fn transaction_state(&mut self) -> &mut AnsiTransactionManager
    where
        Self: Sized,
    {
        &mut self.transaction_state
    }
}

impl GetPgMetadataCache for PgConnection {
    fn get_metadata_cache(&mut self) -> &mut PgMetadataCache {
        &mut self.metadata_cache
    }
}

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

    fn with_prepared_query<'conn, T: QueryFragment<Pg> + QueryId, R>(
        &'conn mut self,
        source: &'_ T,
        f: impl FnOnce(
            MaybeCached<'_, Statement>,
            Vec<Option<Vec<u8>>>,
            &'conn mut RawConnection,
        ) -> QueryResult<R>,
    ) -> QueryResult<R> {
        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 cache = &mut self.statement_cache;
        let raw_conn = &mut self.raw_connection;
        let query = 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(raw_conn, sql, query_name.as_deref(), &metadata)
        });

        f(query?, binds, raw_conn)
    }

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

    fn set_config_options(&mut 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(())
    }
}

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

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

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

    #[test]
    fn malformed_sql_query() {
        let connection = &mut connection();
        let query =
            crate::sql_query("SELECT not_existent FROM also_not_there;").execute(connection);

        if let Err(err) = query {
            if let DatabaseError(_, string) = err {
                assert_eq!(Some(26), string.statement_position());
            } else {
                unreachable!();
            }
        } else {
            unreachable!();
        }
    }

    #[test]
    fn prepared_statements_are_cached() {
        let connection = &mut 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 = &mut 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 = &mut 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 = &mut 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 = &mut connection();
        let query = crate::select(sql::<Integer>("1"));

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

    table! {
        users {
            id -> Integer,
            name -> Text,
        }
    }

    #[test]
    fn inserts_from_select_are_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let query = users::table.filter(users::id.eq(42));
        let insert = query
            .insert_into(users::table)
            .into_columns((users::id, users::name));
        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(1, connection.statement_cache.len());

        let query = users::table.filter(users::id.eq(42)).into_boxed();
        let insert = query
            .insert_into(users::table)
            .into_columns((users::id, users::name));
        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(2, connection.statement_cache.len());
    }

    #[test]
    fn single_inserts_are_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let insert =
            crate::insert_into(users::table).values((users::id.eq(42), users::name.eq("Foo")));

        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(1, connection.statement_cache.len());
    }

    #[test]
    fn dynamic_batch_inserts_are_not_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let insert = crate::insert_into(users::table)
            .values(vec![(users::id.eq(42), users::name.eq("Foo"))]);

        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(0, connection.statement_cache.len());
    }

    #[test]
    fn static_batch_inserts_are_cached() {
        let connection = &mut connection();
        connection.begin_test_transaction().unwrap();

        crate::sql_query(
            "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
        )
        .execute(connection)
        .unwrap();

        let insert =
            crate::insert_into(users::table).values([(users::id.eq(42), users::name.eq("Foo"))]);

        assert_eq!(true, insert.execute(connection).is_ok());
        assert_eq!(1, connection.statement_cache.len());
    }

    #[test]
    fn queries_containing_in_with_vec_are_cached() {
        let connection = &mut connection();
        let one_as_expr = 1.into_sql::<Integer>();
        let query = crate::select(one_as_expr.eq_any(vec![1, 2, 3]));

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

    fn connection() -> PgConnection {
        crate::test_helpers::pg_connection_no_transaction()
    }
}
<|endoftext|>


<commit_before><commit_msg>whitespace fix<commit_after><|endoftext|>


<commit_before>//! Integration tests to make sure alternate backends work.

extern crate mdbook;
extern crate tempfile;

use mdbook::config::Config;
use mdbook::MDBook;
#[cfg(not(windows))]
use std::path::Path;
use tempfile::{Builder as TempFileBuilder, TempDir};

#[test]
fn passing_alternate_backend() {
    let (md, _temp) = dummy_book_with_backend("passing", "true");

    md.build().unwrap();
}

#[test]
fn failing_alternate_backend() {
    let (md, _temp) = dummy_book_with_backend("failing", "false");

    md.build().unwrap_err();
}

#[test]
fn missing_backends_arent_fatal() {
    let (md, _temp) = dummy_book_with_backend("missing", "trduyvbhijnorgevfuhn");

    assert!(md.build().is_ok());
}

#[test]
fn alternate_backend_with_arguments() {
    let (md, _temp) = dummy_book_with_backend("arguments", "echo Hello World!");

    md.build().unwrap();
}

/// Get a command which will pipe `stdin` to the provided file.
#[cfg(not(windows))]
fn tee_command<P: AsRef<Path>>(out_file: P) -> String {
    let out_file = out_file.as_ref();

    if cfg!(windows) {
        format!("cmd.exe /c \"type > {}\"", out_file.display())
    } else {
        format!("tee {}", out_file.display())
    }
}

#[test]
#[cfg(not(windows))]
fn backends_receive_render_context_via_stdin() {
    use mdbook::renderer::RenderContext;
    use std::fs::File;

    let temp = TempFileBuilder::new().prefix("output").tempdir().unwrap();
    let out_file = temp.path().join("out.txt");
    let cmd = tee_command(&out_file);

    let (md, _temp) = dummy_book_with_backend("cat-to-file", &cmd);

    assert!(!out_file.exists());
    md.build().unwrap();
    assert!(out_file.exists());

    let got = RenderContext::from_json(File::open(&out_file).unwrap());
    assert!(got.is_ok());
}

fn dummy_book_with_backend(name: &str, command: &str) -> (MDBook, TempDir) {
    let temp = TempFileBuilder::new().prefix("mdbook").tempdir().unwrap();

    let mut config = Config::default();
    config
        .set(format!("output.{}.command", name), command)
        .unwrap();

    let md = MDBook::init(temp.path())
        .with_config(config)
        .build()
        .unwrap();

    (md, temp)
}
<commit_msg>Make failing_alternate_backend test more platform specific<commit_after>//! Integration tests to make sure alternate backends work.

extern crate mdbook;
extern crate tempfile;

use mdbook::config::Config;
use mdbook::MDBook;
#[cfg(not(windows))]
use std::path::Path;
use tempfile::{Builder as TempFileBuilder, TempDir};

#[test]
fn passing_alternate_backend() {
    let (md, _temp) = dummy_book_with_backend("passing", success_cmd());

    md.build().unwrap();
}

#[test]
fn failing_alternate_backend() {
    let (md, _temp) = dummy_book_with_backend("failing", fail_cmd());

    md.build().unwrap_err();
}

#[test]
fn missing_backends_arent_fatal() {
    let (md, _temp) = dummy_book_with_backend("missing", "trduyvbhijnorgevfuhn");

    assert!(md.build().is_ok());
}

#[test]
fn alternate_backend_with_arguments() {
    let (md, _temp) = dummy_book_with_backend("arguments", "echo Hello World!");

    md.build().unwrap();
}

/// Get a command which will pipe `stdin` to the provided file.
#[cfg(not(windows))]
fn tee_command<P: AsRef<Path>>(out_file: P) -> String {
    let out_file = out_file.as_ref();

    if cfg!(windows) {
        format!("cmd.exe /c \"type > {}\"", out_file.display())
    } else {
        format!("tee {}", out_file.display())
    }
}

#[test]
#[cfg(not(windows))]
fn backends_receive_render_context_via_stdin() {
    use mdbook::renderer::RenderContext;
    use std::fs::File;

    let temp = TempFileBuilder::new().prefix("output").tempdir().unwrap();
    let out_file = temp.path().join("out.txt");
    let cmd = tee_command(&out_file);

    let (md, _temp) = dummy_book_with_backend("cat-to-file", &cmd);

    assert!(!out_file.exists());
    md.build().unwrap();
    assert!(out_file.exists());

    let got = RenderContext::from_json(File::open(&out_file).unwrap());
    assert!(got.is_ok());
}

fn dummy_book_with_backend(name: &str, command: &str) -> (MDBook, TempDir) {
    let temp = TempFileBuilder::new().prefix("mdbook").tempdir().unwrap();

    let mut config = Config::default();
    config
        .set(format!("output.{}.command", name), command)
        .unwrap();

    let md = MDBook::init(temp.path())
        .with_config(config)
        .build()
        .unwrap();

    (md, temp)
}

fn fail_cmd() -> &'static str {
    if cfg!(windows) {
        r#"cmd.exe /c "exit 1""#
    } else {
        "false"
    }
}

fn success_cmd() -> &'static str {
    if cfg!(windows) {
        r#"cmd.exe /c "exit 0""#
    } else {
        "true"
    }
}
<|endoftext|>