<commit_before>// Functionality that is shared between the cxxbridge macro and the cmd.

pub mod atom;
pub mod attrs;
pub mod check;
pub mod derive;
mod discriminant;
mod doc;
pub mod error;
pub mod file;
pub mod ident;
mod impls;
mod improper;
pub mod instantiate;
pub mod mangle;
pub mod map;
mod names;
pub mod namespace;
mod parse;
mod pod;
pub mod qualified;
pub mod report;
pub mod resolve;
pub mod set;
pub mod symbol;
mod tokens;
mod toposort;
pub mod trivial;
pub mod types;
mod visit;

use self::attrs::OtherAttrs;
use self::namespace::Namespace;
use self::parse::kw;
use self::symbol::Symbol;
use proc_macro2::{Ident, Span};
use syn::punctuated::Punctuated;
use syn::token::{Brace, Bracket, Paren};
use syn::{Attribute, Expr, Generics, Lifetime, LitInt, Token, Type as RustType};

pub use self::atom::Atom;
pub use self::derive::{Derive, Trait};
pub use self::discriminant::Discriminant;
pub use self::doc::Doc;
pub use self::names::ForeignName;
pub use self::parse::parse_items;
pub use self::types::Types;

pub enum Api {
    Include(Include),
    Struct(Struct),
    Enum(Enum),
    CxxType(ExternType),
    CxxFunction(ExternFn),
    RustType(ExternType),
    RustFunction(ExternFn),
    TypeAlias(TypeAlias),
    Impl(Impl),
}

pub struct Include {
    pub path: String,
    pub kind: IncludeKind,
    pub begin_span: Span,
    pub end_span: Span,
}

/// Whether to emit `#include "path"` or `#include <path>`.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IncludeKind {
    /// `#include "quoted/path/to"`
    Quoted,
    /// `#include <bracketed/path/to>`
    Bracketed,
}

pub struct ExternType {
    pub lang: Lang,
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub type_token: Token![type],
    pub name: Pair,
    pub generics: Lifetimes,
    pub colon_token: Option<Token![:]>,
    pub bounds: Vec<Derive>,
    pub semi_token: Token![;],
    pub trusted: bool,
}

pub struct Struct {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub struct_token: Token![struct],
    pub name: Pair,
    pub generics: Lifetimes,
    pub brace_token: Brace,
    pub fields: Vec<Var>,
}

pub struct Enum {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub enum_token: Token![enum],
    pub name: Pair,
    pub generics: Lifetimes,
    pub brace_token: Brace,
    pub variants: Vec<Variant>,
    pub variants_from_header: bool,
    pub variants_from_header_attr: Option<Attribute>,
    pub repr: EnumRepr,
    pub explicit_repr: bool,
}

pub enum EnumRepr {
    Native { atom: Atom, repr_type: Type },
    #[cfg(feature = "experimental")]
    Foreign { rust_type: syn::Path },
}

pub struct ExternFn {
    pub lang: Lang,
    pub doc: Doc,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub name: Pair,
    pub sig: Signature,
    pub semi_token: Token![;],
    pub trusted: bool,
}

pub struct TypeAlias {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub type_token: Token![type],
    pub name: Pair,
    pub generics: Lifetimes,
    pub eq_token: Token![=],
    pub ty: RustType,
    pub semi_token: Token![;],
}

pub struct Impl {
    pub impl_token: Token![impl],
    pub impl_generics: Lifetimes,
    pub negative: bool,
    pub ty: Type,
    pub ty_generics: Lifetimes,
    pub brace_token: Brace,
    pub negative_token: Option<Token![!]>,
}

#[derive(Clone, Default)]
pub struct Lifetimes {
    pub lt_token: Option<Token![<]>,
    pub lifetimes: Punctuated<Lifetime, Token![,]>,
    pub gt_token: Option<Token![>]>,
}

pub struct Signature {
    pub unsafety: Option<Token![unsafe]>,
    pub fn_token: Token![fn],
    pub generics: Generics,
    pub receiver: Option<Receiver>,
    pub args: Punctuated<Var, Token![,]>,
    pub ret: Option<Type>,
    pub throws: bool,
    pub paren_token: Paren,
    pub throws_tokens: Option<(kw::Result, Token![<], Token![>])>,
}

pub struct Var {
    pub doc: Doc,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub name: Pair,
    pub colon_token: Token![:],
    pub ty: Type,
}

pub struct Receiver {
    pub pinned: bool,
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutable: bool,
    pub var: Token![self],
    pub ty: NamedType,
    pub colon_token: Token![:],
    pub shorthand: bool,
    pub pin_tokens: Option<(kw::Pin, Token![<], Token![>])>,
    pub mutability: Option<Token![mut]>,
}

pub struct Variant {
    pub doc: Doc,
    pub attrs: OtherAttrs,
    pub name: Pair,
    pub discriminant: Discriminant,
    pub expr: Option<Expr>,
}

pub enum Type {
    Ident(NamedType),
    RustBox(Box<Ty1>),
    RustVec(Box<Ty1>),
    UniquePtr(Box<Ty1>),
    SharedPtr(Box<Ty1>),
    WeakPtr(Box<Ty1>),
    Ref(Box<Ref>),
    Ptr(Box<Ptr>),
    Str(Box<Ref>),
    CxxVector(Box<Ty1>),
    Fn(Box<Signature>),
    Void(Span),
    SliceRef(Box<SliceRef>),
    Array(Box<Array>),
}

pub struct Ty1 {
    pub name: Ident,
    pub langle: Token![<],
    pub inner: Type,
    pub rangle: Token![>],
}

pub struct Ref {
    pub pinned: bool,
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutable: bool,
    pub inner: Type,
    pub pin_tokens: Option<(kw::Pin, Token![<], Token![>])>,
    pub mutability: Option<Token![mut]>,
}

pub struct Ptr {
    pub star: Token![*],
    pub mutable: bool,
    pub inner: Type,
    pub mutability: Option<Token![mut]>,
    pub constness: Option<Token![const]>,
}

pub struct SliceRef {
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutable: bool,
    pub bracket: Bracket,
    pub inner: Type,
    pub mutability: Option<Token![mut]>,
}

pub struct Array {
    pub bracket: Bracket,
    pub inner: Type,
    pub semi_token: Token![;],
    pub len: usize,
    pub len_token: LitInt,
}

#[derive(Copy, Clone, PartialEq)]
pub enum Lang {
    Cxx,
    Rust,
}

// An association of a defined Rust name with a fully resolved, namespace
// qualified C++ name.
#[derive(Clone)]
pub struct Pair {
    pub namespace: Namespace,
    pub cxx: ForeignName,
    pub rust: Ident,
}

// Wrapper for a type which needs to be resolved before it can be printed in
// C++.
#[derive(PartialEq, Eq, Hash)]
pub struct NamedType {
    pub rust: Ident,
    pub generics: Lifetimes,
}
<commit_msg>Format with rustfmt 1.4.38<commit_after>// Functionality that is shared between the cxxbridge macro and the cmd.

pub mod atom;
pub mod attrs;
pub mod check;
pub mod derive;
mod discriminant;
mod doc;
pub mod error;
pub mod file;
pub mod ident;
mod impls;
mod improper;
pub mod instantiate;
pub mod mangle;
pub mod map;
mod names;
pub mod namespace;
mod parse;
mod pod;
pub mod qualified;
pub mod report;
pub mod resolve;
pub mod set;
pub mod symbol;
mod tokens;
mod toposort;
pub mod trivial;
pub mod types;
mod visit;

use self::attrs::OtherAttrs;
use self::namespace::Namespace;
use self::parse::kw;
use self::symbol::Symbol;
use proc_macro2::{Ident, Span};
use syn::punctuated::Punctuated;
use syn::token::{Brace, Bracket, Paren};
use syn::{Attribute, Expr, Generics, Lifetime, LitInt, Token, Type as RustType};

pub use self::atom::Atom;
pub use self::derive::{Derive, Trait};
pub use self::discriminant::Discriminant;
pub use self::doc::Doc;
pub use self::names::ForeignName;
pub use self::parse::parse_items;
pub use self::types::Types;

pub enum Api {
    Include(Include),
    Struct(Struct),
    Enum(Enum),
    CxxType(ExternType),
    CxxFunction(ExternFn),
    RustType(ExternType),
    RustFunction(ExternFn),
    TypeAlias(TypeAlias),
    Impl(Impl),
}

pub struct Include {
    pub path: String,
    pub kind: IncludeKind,
    pub begin_span: Span,
    pub end_span: Span,
}

/// Whether to emit `#include "path"` or `#include <path>`.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IncludeKind {
    /// `#include "quoted/path/to"`
    Quoted,
    /// `#include <bracketed/path/to>`
    Bracketed,
}

pub struct ExternType {
    pub lang: Lang,
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub type_token: Token![type],
    pub name: Pair,
    pub generics: Lifetimes,
    pub colon_token: Option<Token![:]>,
    pub bounds: Vec<Derive>,
    pub semi_token: Token![;],
    pub trusted: bool,
}

pub struct Struct {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub struct_token: Token![struct],
    pub name: Pair,
    pub generics: Lifetimes,
    pub brace_token: Brace,
    pub fields: Vec<Var>,
}

pub struct Enum {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub enum_token: Token![enum],
    pub name: Pair,
    pub generics: Lifetimes,
    pub brace_token: Brace,
    pub variants: Vec<Variant>,
    pub variants_from_header: bool,
    pub variants_from_header_attr: Option<Attribute>,
    pub repr: EnumRepr,
    pub explicit_repr: bool,
}

pub enum EnumRepr {
    Native {
        atom: Atom,
        repr_type: Type,
    },
    #[cfg(feature = "experimental")]
    Foreign {
        rust_type: syn::Path,
    },
}

pub struct ExternFn {
    pub lang: Lang,
    pub doc: Doc,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub name: Pair,
    pub sig: Signature,
    pub semi_token: Token![;],
    pub trusted: bool,
}

pub struct TypeAlias {
    pub doc: Doc,
    pub derives: Vec<Derive>,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub type_token: Token![type],
    pub name: Pair,
    pub generics: Lifetimes,
    pub eq_token: Token![=],
    pub ty: RustType,
    pub semi_token: Token![;],
}

pub struct Impl {
    pub impl_token: Token![impl],
    pub impl_generics: Lifetimes,
    pub negative: bool,
    pub ty: Type,
    pub ty_generics: Lifetimes,
    pub brace_token: Brace,
    pub negative_token: Option<Token![!]>,
}

#[derive(Clone, Default)]
pub struct Lifetimes {
    pub lt_token: Option<Token![<]>,
    pub lifetimes: Punctuated<Lifetime, Token![,]>,
    pub gt_token: Option<Token![>]>,
}

pub struct Signature {
    pub unsafety: Option<Token![unsafe]>,
    pub fn_token: Token![fn],
    pub generics: Generics,
    pub receiver: Option<Receiver>,
    pub args: Punctuated<Var, Token![,]>,
    pub ret: Option<Type>,
    pub throws: bool,
    pub paren_token: Paren,
    pub throws_tokens: Option<(kw::Result, Token![<], Token![>])>,
}

pub struct Var {
    pub doc: Doc,
    pub attrs: OtherAttrs,
    pub visibility: Token![pub],
    pub name: Pair,
    pub colon_token: Token![:],
    pub ty: Type,
}

pub struct Receiver {
    pub pinned: bool,
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutable: bool,
    pub var: Token![self],
    pub ty: NamedType,
    pub colon_token: Token![:],
    pub shorthand: bool,
    pub pin_tokens: Option<(kw::Pin, Token![<], Token![>])>,
    pub mutability: Option<Token![mut]>,
}

pub struct Variant {
    pub doc: Doc,
    pub attrs: OtherAttrs,
    pub name: Pair,
    pub discriminant: Discriminant,
    pub expr: Option<Expr>,
}

pub enum Type {
    Ident(NamedType),
    RustBox(Box<Ty1>),
    RustVec(Box<Ty1>),
    UniquePtr(Box<Ty1>),
    SharedPtr(Box<Ty1>),
    WeakPtr(Box<Ty1>),
    Ref(Box<Ref>),
    Ptr(Box<Ptr>),
    Str(Box<Ref>),
    CxxVector(Box<Ty1>),
    Fn(Box<Signature>),
    Void(Span),
    SliceRef(Box<SliceRef>),
    Array(Box<Array>),
}

pub struct Ty1 {
    pub name: Ident,
    pub langle: Token![<],
    pub inner: Type,
    pub rangle: Token![>],
}

pub struct Ref {
    pub pinned: bool,
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutable: bool,
    pub inner: Type,
    pub pin_tokens: Option<(kw::Pin, Token![<], Token![>])>,
    pub mutability: Option<Token![mut]>,
}

pub struct Ptr {
    pub star: Token![*],
    pub mutable: bool,
    pub inner: Type,
    pub mutability: Option<Token![mut]>,
    pub constness: Option<Token![const]>,
}

pub struct SliceRef {
    pub ampersand: Token![&],
    pub lifetime: Option<Lifetime>,
    pub mutable: bool,
    pub bracket: Bracket,
    pub inner: Type,
    pub mutability: Option<Token![mut]>,
}

pub struct Array {
    pub bracket: Bracket,
    pub inner: Type,
    pub semi_token: Token![;],
    pub len: usize,
    pub len_token: LitInt,
}

#[derive(Copy, Clone, PartialEq)]
pub enum Lang {
    Cxx,
    Rust,
}

// An association of a defined Rust name with a fully resolved, namespace
// qualified C++ name.
#[derive(Clone)]
pub struct Pair {
    pub namespace: Namespace,
    pub cxx: ForeignName,
    pub rust: Ident,
}

// Wrapper for a type which needs to be resolved before it can be printed in
// C++.
#[derive(PartialEq, Eq, Hash)]
pub struct NamedType {
    pub rust: Ident,
    pub generics: Lifetimes,
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;

use std::str::FromStr;
use std::fmt;

use cargo::util::{Cfg, CfgExpr};
use cargotest::{is_nightly, rustc_host};
use cargotest::support::registry::Package;
use cargotest::support::{project, execs};
use hamcrest::assert_that;

macro_rules! c {
    ($a:ident) => (
        Cfg::Name(stringify!($a).to_string())
    );
    ($a:ident = $e:expr) => (
        Cfg::KeyPair(stringify!($a).to_string(), $e.to_string())
    );
}

macro_rules! e {
    (any($($t:tt),*)) => (CfgExpr::Any(vec![$(e!($t)),*]));
    (all($($t:tt),*)) => (CfgExpr::All(vec![$(e!($t)),*]));
    (not($($t:tt)*)) => (CfgExpr::Not(Box::new(e!($($t)*))));
    (($($t:tt)*)) => (e!($($t)*));
    ($($t:tt)*) => (CfgExpr::Value(c!($($t)*)));
}

fn good<T>(s: &str, expected: T)
    where T: FromStr + PartialEq + fmt::Debug,
          T::Err: fmt::Display
{
    let c = match T::from_str(s) {
        Ok(c) => c,
        Err(e) => panic!("failed to parse `{}`: {}", s, e),
    };
    assert_eq!(c, expected);
}

fn bad<T>(s: &str, err: &str)
    where T: FromStr + fmt::Display, T::Err: fmt::Display
{
    let e = match T::from_str(s) {
        Ok(cfg) => panic!("expected `{}` to not parse but got {}", s, cfg),
        Err(e) => e.to_string(),
    };
    assert!(e.contains(err), "when parsing `{}`,\n\"{}\" not contained \
                              inside: {}", s, err, e);
}

#[test]
fn cfg_syntax() {
    good("foo", c!(foo));
    good("_bar", c!(_bar));
    good(" foo", c!(foo));
    good(" foo  ", c!(foo));
    good(" foo  = \"bar\"", c!(foo = "bar"));
    good("foo=\"\"", c!(foo = ""));
    good(" foo=\"3\"      ", c!(foo = "3"));
    good("foo = \"3 e\"", c!(foo = "3 e"));
}

#[test]
fn cfg_syntax_bad() {
    bad::<Cfg>("", "found nothing");
    bad::<Cfg>(" ", "found nothing");
    bad::<Cfg>("\t", "unexpected character");
    bad::<Cfg>("7", "unexpected character");
    bad::<Cfg>("=", "expected identifier");
    bad::<Cfg>(",", "expected identifier");
    bad::<Cfg>("(", "expected identifier");
    bad::<Cfg>("foo (", "malformed cfg value");
    bad::<Cfg>("bar =", "expected a string");
    bad::<Cfg>("bar = \"", "unterminated string");
    bad::<Cfg>("foo, bar", "malformed cfg value");
}

#[test]
fn cfg_expr() {
    good("foo", e!(foo));
    good("_bar", e!(_bar));
    good(" foo", e!(foo));
    good(" foo  ", e!(foo));
    good(" foo  = \"bar\"", e!(foo = "bar"));
    good("foo=\"\"", e!(foo = ""));
    good(" foo=\"3\"      ", e!(foo = "3"));
    good("foo = \"3 e\"", e!(foo = "3 e"));

    good("all()", e!(all()));
    good("all(a)", e!(all(a)));
    good("all(a, b)", e!(all(a, b)));
    good("all(a, )", e!(all(a)));
    good("not(a = \"b\")", e!(not(a = "b")));
    good("not(all(a))", e!(not(all(a))));
}

#[test]
fn cfg_expr_bad() {
    bad::<CfgExpr>(" ", "found nothing");
    bad::<CfgExpr>(" all", "expected `(`");
    bad::<CfgExpr>("all(a", "expected `)`");
    bad::<CfgExpr>("not", "expected `(`");
    bad::<CfgExpr>("not(a", "expected `)`");
    bad::<CfgExpr>("a = ", "expected a string");
    bad::<CfgExpr>("all(not())", "expected identifier");
    bad::<CfgExpr>("foo(a)", "consider using all() or any() explicitly");
}

#[test]
fn cfg_matches() {
    assert!(e!(foo).matches(&[c!(bar), c!(foo), c!(baz)]));
    assert!(e!(any(foo)).matches(&[c!(bar), c!(foo), c!(baz)]));
    assert!(e!(any(foo, bar)).matches(&[c!(bar)]));
    assert!(e!(any(foo, bar)).matches(&[c!(foo)]));
    assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
    assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
    assert!(e!(not(foo)).matches(&[c!(bar)]));
    assert!(e!(not(foo)).matches(&[]));
    assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(bar)]));
    assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo), c!(bar)]));

    assert!(!e!(foo).matches(&[]));
    assert!(!e!(foo).matches(&[c!(bar)]));
    assert!(!e!(foo).matches(&[c!(fo)]));
    assert!(!e!(any(foo)).matches(&[]));
    assert!(!e!(any(foo)).matches(&[c!(bar)]));
    assert!(!e!(any(foo)).matches(&[c!(bar), c!(baz)]));
    assert!(!e!(all(foo)).matches(&[c!(bar), c!(baz)]));
    assert!(!e!(all(foo, bar)).matches(&[c!(bar)]));
    assert!(!e!(all(foo, bar)).matches(&[c!(foo)]));
    assert!(!e!(all(foo, bar)).matches(&[]));
    assert!(!e!(not(bar)).matches(&[c!(bar)]));
    assert!(!e!(not(bar)).matches(&[c!(baz), c!(bar)]));
    assert!(!e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo)]));
}

#[test]
fn cfg_easy() {
    if !is_nightly() { return }

    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(unix)'.dependencies]
            b = { path = 'b' }
            [target."cfg(windows)".dependencies]
            b = { path = 'b' }
        "#)
        .file("src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build").arg("-v"),
                execs().with_status(0));
}

#[test]
fn dont_include() {
    if !is_nightly() { return }

    let other_family = if cfg!(unix) {"windows"} else {"unix"};
    let p = project("foo")
        .file("Cargo.toml", &format!(r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg({})'.dependencies]
            b = {{ path = 'b' }}
        "#, other_family))
        .file("src/lib.rs", "")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr("\
[COMPILING] a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}

#[test]
fn works_through_the_registry() {
    if !is_nightly() { return }

    Package::new("foo", "0.1.0").publish();
    Package::new("bar", "0.1.0")
            .target_dep("foo", "0.1.0", "'cfg(unix)'")
            .target_dep("foo", "0.1.0", "'cfg(windows)'")
            .publish();

    let p = project("a")
        .file("Cargo.toml", &r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = "0.1.0"
        "#)
        .file("src/lib.rs", "extern crate bar;");

    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr("\
[UPDATING] registry [..]
[DOWNLOADING] [..]
[DOWNLOADING] [..]
[COMPILING] foo v0.1.0
[COMPILING] bar v0.1.0
[COMPILING] a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}

#[test]
fn bad_target_spec() {
    let p = project("a")
        .file("Cargo.toml", &r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(4)'.dependencies]
            bar = "0.1.0"
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(101).with_stderr("\
[ERROR] failed to parse manifest at `[..]`

Caused by:
  failed to parse `4` as a cfg expression

Caused by:
  unexpected character in cfg `4`, [..]
"));
}

#[test]
fn bad_target_spec2() {
    let p = project("a")
        .file("Cargo.toml", &r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(foo =)'.dependencies]
            bar = "0.1.0"
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(101).with_stderr("\
[ERROR] failed to parse manifest at `[..]`

Caused by:
  failed to parse `foo =` as a cfg expression

Caused by:
  expected a string, found nothing
"));
}

#[test]
fn multiple_match_ok() {
    if !is_nightly() { return }

    let p = project("foo")
        .file("Cargo.toml", &format!(r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(unix)'.dependencies]
            b = {{ path = 'b' }}
            [target.'cfg(target_family = "unix")'.dependencies]
            b = {{ path = 'b' }}
            [target."cfg(windows)".dependencies]
            b = {{ path = 'b' }}
            [target.'cfg(target_family = "windows")'.dependencies]
            b = {{ path = 'b' }}
            [target."cfg(any(windows, unix))".dependencies]
            b = {{ path = 'b' }}

            [target.{}.dependencies]
            b = {{ path = 'b' }}
        "#, rustc_host()))
        .file("src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build").arg("-v"),
                execs().with_status(0));
}

#[test]
fn any_ok() {
    if !is_nightly() { return }

    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target."cfg(any(windows, unix))".dependencies]
            b = { path = 'b' }
        "#)
        .file("src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build").arg("-v"),
                execs().with_status(0));
}
<commit_msg>add test cfg/ignore_version_from_other_platform<commit_after>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;

use std::str::FromStr;
use std::fmt;

use cargo::util::{Cfg, CfgExpr};
use cargotest::{is_nightly, rustc_host};
use cargotest::support::registry::Package;
use cargotest::support::{project, execs};
use hamcrest::assert_that;

macro_rules! c {
    ($a:ident) => (
        Cfg::Name(stringify!($a).to_string())
    );
    ($a:ident = $e:expr) => (
        Cfg::KeyPair(stringify!($a).to_string(), $e.to_string())
    );
}

macro_rules! e {
    (any($($t:tt),*)) => (CfgExpr::Any(vec![$(e!($t)),*]));
    (all($($t:tt),*)) => (CfgExpr::All(vec![$(e!($t)),*]));
    (not($($t:tt)*)) => (CfgExpr::Not(Box::new(e!($($t)*))));
    (($($t:tt)*)) => (e!($($t)*));
    ($($t:tt)*) => (CfgExpr::Value(c!($($t)*)));
}

fn good<T>(s: &str, expected: T)
    where T: FromStr + PartialEq + fmt::Debug,
          T::Err: fmt::Display
{
    let c = match T::from_str(s) {
        Ok(c) => c,
        Err(e) => panic!("failed to parse `{}`: {}", s, e),
    };
    assert_eq!(c, expected);
}

fn bad<T>(s: &str, err: &str)
    where T: FromStr + fmt::Display, T::Err: fmt::Display
{
    let e = match T::from_str(s) {
        Ok(cfg) => panic!("expected `{}` to not parse but got {}", s, cfg),
        Err(e) => e.to_string(),
    };
    assert!(e.contains(err), "when parsing `{}`,\n\"{}\" not contained \
                              inside: {}", s, err, e);
}

#[test]
fn cfg_syntax() {
    good("foo", c!(foo));
    good("_bar", c!(_bar));
    good(" foo", c!(foo));
    good(" foo  ", c!(foo));
    good(" foo  = \"bar\"", c!(foo = "bar"));
    good("foo=\"\"", c!(foo = ""));
    good(" foo=\"3\"      ", c!(foo = "3"));
    good("foo = \"3 e\"", c!(foo = "3 e"));
}

#[test]
fn cfg_syntax_bad() {
    bad::<Cfg>("", "found nothing");
    bad::<Cfg>(" ", "found nothing");
    bad::<Cfg>("\t", "unexpected character");
    bad::<Cfg>("7", "unexpected character");
    bad::<Cfg>("=", "expected identifier");
    bad::<Cfg>(",", "expected identifier");
    bad::<Cfg>("(", "expected identifier");
    bad::<Cfg>("foo (", "malformed cfg value");
    bad::<Cfg>("bar =", "expected a string");
    bad::<Cfg>("bar = \"", "unterminated string");
    bad::<Cfg>("foo, bar", "malformed cfg value");
}

#[test]
fn cfg_expr() {
    good("foo", e!(foo));
    good("_bar", e!(_bar));
    good(" foo", e!(foo));
    good(" foo  ", e!(foo));
    good(" foo  = \"bar\"", e!(foo = "bar"));
    good("foo=\"\"", e!(foo = ""));
    good(" foo=\"3\"      ", e!(foo = "3"));
    good("foo = \"3 e\"", e!(foo = "3 e"));

    good("all()", e!(all()));
    good("all(a)", e!(all(a)));
    good("all(a, b)", e!(all(a, b)));
    good("all(a, )", e!(all(a)));
    good("not(a = \"b\")", e!(not(a = "b")));
    good("not(all(a))", e!(not(all(a))));
}

#[test]
fn cfg_expr_bad() {
    bad::<CfgExpr>(" ", "found nothing");
    bad::<CfgExpr>(" all", "expected `(`");
    bad::<CfgExpr>("all(a", "expected `)`");
    bad::<CfgExpr>("not", "expected `(`");
    bad::<CfgExpr>("not(a", "expected `)`");
    bad::<CfgExpr>("a = ", "expected a string");
    bad::<CfgExpr>("all(not())", "expected identifier");
    bad::<CfgExpr>("foo(a)", "consider using all() or any() explicitly");
}

#[test]
fn cfg_matches() {
    assert!(e!(foo).matches(&[c!(bar), c!(foo), c!(baz)]));
    assert!(e!(any(foo)).matches(&[c!(bar), c!(foo), c!(baz)]));
    assert!(e!(any(foo, bar)).matches(&[c!(bar)]));
    assert!(e!(any(foo, bar)).matches(&[c!(foo)]));
    assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
    assert!(e!(all(foo, bar)).matches(&[c!(foo), c!(bar)]));
    assert!(e!(not(foo)).matches(&[c!(bar)]));
    assert!(e!(not(foo)).matches(&[]));
    assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(bar)]));
    assert!(e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo), c!(bar)]));

    assert!(!e!(foo).matches(&[]));
    assert!(!e!(foo).matches(&[c!(bar)]));
    assert!(!e!(foo).matches(&[c!(fo)]));
    assert!(!e!(any(foo)).matches(&[]));
    assert!(!e!(any(foo)).matches(&[c!(bar)]));
    assert!(!e!(any(foo)).matches(&[c!(bar), c!(baz)]));
    assert!(!e!(all(foo)).matches(&[c!(bar), c!(baz)]));
    assert!(!e!(all(foo, bar)).matches(&[c!(bar)]));
    assert!(!e!(all(foo, bar)).matches(&[c!(foo)]));
    assert!(!e!(all(foo, bar)).matches(&[]));
    assert!(!e!(not(bar)).matches(&[c!(bar)]));
    assert!(!e!(not(bar)).matches(&[c!(baz), c!(bar)]));
    assert!(!e!(any((not(foo)), (all(foo, bar)))).matches(&[c!(foo)]));
}

#[test]
fn cfg_easy() {
    if !is_nightly() { return }

    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(unix)'.dependencies]
            b = { path = 'b' }
            [target."cfg(windows)".dependencies]
            b = { path = 'b' }
        "#)
        .file("src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build").arg("-v"),
                execs().with_status(0));
}

#[test]
fn dont_include() {
    if !is_nightly() { return }

    let other_family = if cfg!(unix) {"windows"} else {"unix"};
    let p = project("foo")
        .file("Cargo.toml", &format!(r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg({})'.dependencies]
            b = {{ path = 'b' }}
        "#, other_family))
        .file("src/lib.rs", "")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr("\
[COMPILING] a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}

#[test]
fn works_through_the_registry() {
    if !is_nightly() { return }

    Package::new("foo", "0.1.0").publish();
    Package::new("bar", "0.1.0")
            .target_dep("foo", "0.1.0", "'cfg(unix)'")
            .target_dep("foo", "0.1.0", "'cfg(windows)'")
            .publish();

    let p = project("a")
        .file("Cargo.toml", &r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = "0.1.0"
        "#)
        .file("src/lib.rs", "extern crate bar;");

    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr("\
[UPDATING] registry [..]
[DOWNLOADING] [..]
[DOWNLOADING] [..]
[COMPILING] foo v0.1.0
[COMPILING] bar v0.1.0
[COMPILING] a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}

#[test]
fn ignore_version_from_other_platform() {
    let this_family = if cfg!(unix) {"unix"} else {"windows"};
    let other_family = if cfg!(unix) {"windows"} else {"unix"};
    Package::new("foo", "0.1.0").publish();
    Package::new("foo", "0.2.0").publish();

    let p = project("a")
        .file("Cargo.toml", &format!(r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg({})'.dependencies]
            foo = "0.1.0"

            [target.'cfg({})'.dependencies]
            foo = "0.2.0"
        "#, this_family, other_family))
        .file("src/lib.rs", "extern crate foo;");

    assert_that(p.cargo_process("build"),
                execs().with_status(0).with_stderr("\
[UPDATING] registry [..]
[DOWNLOADING] [..]
[COMPILING] foo v0.1.0
[COMPILING] a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}

#[test]
fn bad_target_spec() {
    let p = project("a")
        .file("Cargo.toml", &r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(4)'.dependencies]
            bar = "0.1.0"
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(101).with_stderr("\
[ERROR] failed to parse manifest at `[..]`

Caused by:
  failed to parse `4` as a cfg expression

Caused by:
  unexpected character in cfg `4`, [..]
"));
}

#[test]
fn bad_target_spec2() {
    let p = project("a")
        .file("Cargo.toml", &r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(foo =)'.dependencies]
            bar = "0.1.0"
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("build"),
                execs().with_status(101).with_stderr("\
[ERROR] failed to parse manifest at `[..]`

Caused by:
  failed to parse `foo =` as a cfg expression

Caused by:
  expected a string, found nothing
"));
}

#[test]
fn multiple_match_ok() {
    if !is_nightly() { return }

    let p = project("foo")
        .file("Cargo.toml", &format!(r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target.'cfg(unix)'.dependencies]
            b = {{ path = 'b' }}
            [target.'cfg(target_family = "unix")'.dependencies]
            b = {{ path = 'b' }}
            [target."cfg(windows)".dependencies]
            b = {{ path = 'b' }}
            [target.'cfg(target_family = "windows")'.dependencies]
            b = {{ path = 'b' }}
            [target."cfg(any(windows, unix))".dependencies]
            b = {{ path = 'b' }}

            [target.{}.dependencies]
            b = {{ path = 'b' }}
        "#, rustc_host()))
        .file("src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build").arg("-v"),
                execs().with_status(0));
}

#[test]
fn any_ok() {
    if !is_nightly() { return }

    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "a"
            version = "0.0.1"
            authors = []

            [target."cfg(any(windows, unix))".dependencies]
            b = { path = 'b' }
        "#)
        .file("src/lib.rs", "extern crate b;")
        .file("b/Cargo.toml", r#"
            [package]
            name = "b"
            version = "0.0.1"
            authors = []
        "#)
        .file("b/src/lib.rs", "");
    assert_that(p.cargo_process("build").arg("-v"),
                execs().with_status(0));
}
<|endoftext|>


<commit_before>#![feature(globs,macro_rules,phase)]

#[phase(plugin,link)]
extern crate nom;

use nom::{IResult,Producer,FileProducer,ProducerState,FlatMapper,Mapper,Mapper2,line_ending,not_line_ending, space, alphanumeric, is_alphanumeric};
use nom::IResult::*;

use std::str;
use std::fmt::Show;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
o!(comment_body<&[u8],&[u8]> semicolon ~ not_line_ending ~ );
o!(comment<&[u8], ()> comment_body line_ending ~ empty_result ~);
opt!(opt_comment<&[u8],&[u8]> comment_body);

tag!(lsb "[".as_bytes());
tag!(rsb "]".as_bytes());
fn category_name(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == ']' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}
o!(category<&[u8], &[u8]> lsb ~ category_name ~ rsb line_ending);

tag!(equal "=".as_bytes());
fn not_equal(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == '=' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

fn value_parser(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == '\n' as u8 || input[idx] == ';' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

opt!(opt_line_ending<&[u8],&[u8]> line_ending);
o!(value<&[u8],&[u8]> space equal space ~ value_parser ~ space opt_comment opt_line_ending);
chain!(key_value<&[u8],(&[u8],&[u8])>, ||{(key, val)},  key: alphanumeric, val: value,);

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = Done((), ini_file.as_bytes()).flat_map(comment);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]
parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(category);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), str::from_utf8(o)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category".as_bytes()));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}
<commit_msg>parse ini category name as text<commit_after>#![feature(globs,macro_rules,phase)]

#[phase(plugin,link)]
extern crate nom;

use nom::{IResult,Producer,FileProducer,ProducerState,FlatMapper,Mapper,Mapper2,line_ending,not_line_ending, space, alphanumeric, is_alphanumeric};
use nom::IResult::*;

use std::str;
use std::fmt::Show;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
o!(comment_body<&[u8],&[u8]> semicolon ~ not_line_ending ~ );
o!(comment<&[u8], ()> comment_body line_ending ~ empty_result ~);
opt!(opt_comment<&[u8],&[u8]> comment_body);

tag!(lsb "[".as_bytes());
tag!(rsb "]".as_bytes());
fn category_name(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in range(0, input.len()) {
    if input[idx] == ']' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx)).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}
o!(category<&[u8], &str> lsb ~ category_name ~ rsb line_ending);

tag!(equal "=".as_bytes());
fn not_equal(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == '=' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

fn value_parser(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == '\n' as u8 || input[idx] == ';' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

opt!(opt_line_ending<&[u8],&[u8]> line_ending);
o!(value<&[u8],&[u8]> space equal space ~ value_parser ~ space opt_comment opt_line_ending);
chain!(key_value<&[u8],(&[u8],&[u8])>, ||{(key, val)},  key: alphanumeric, val: value,);

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = Done((), ini_file.as_bytes()).flat_map(comment);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]
parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(category);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use enums::*;

/// Parses a SPIR-V document.
pub fn parse_spirv(data: &[u8]) -> Result<Spirv, ParseError> {
    if data.len() < 20 {
        return Err(ParseError::MissingHeader);
    }

    // we need to determine whether we are in big endian order or little endian order depending
    // on the magic number at the start of the file
    let data = if data[0] == 0x07 && data[1] == 0x23 && data[2] == 0x02 && data[3] == 0x03 {
        // big endian
        data.chunks(4)
            .map(|c| {
                     ((c[0] as u32) << 24) | ((c[1] as u32) << 16) | ((c[2] as u32) << 8) |
                         c[3] as u32
                 })
            .collect::<Vec<_>>()

    } else if data[3] == 0x07 && data[2] == 0x23 && data[1] == 0x02 && data[0] == 0x03 {
        // little endian
        data.chunks(4)
            .map(|c| {
                     ((c[3] as u32) << 24) | ((c[2] as u32) << 16) | ((c[1] as u32) << 8) |
                         c[0] as u32
                 })
            .collect::<Vec<_>>()

    } else {
        return Err(ParseError::MissingHeader);
    };

    parse_u32s(&data)
}

/// Parses a SPIR-V document from a list of u32s.
///
/// Endianess has already been handled.
fn parse_u32s(i: &[u32]) -> Result<Spirv, ParseError> {
    if i.len() < 5 {
        return Err(ParseError::MissingHeader);
    }

    if i[0] != 0x07230203 {
        return Err(ParseError::WrongHeader);
    }

    let version = (((i[1] & 0x00ff0000) >> 16) as u8, ((i[1] & 0x0000ff00) >> 8) as u8);

    let instructions = {
        let mut ret = Vec::new();
        let mut i = &i[5 ..];
        while i.len() >= 1 {
            let (instruction, rest) = parse_instruction(i)?;
            ret.push(instruction);
            i = rest;
        }
        ret
    };

    Ok(Spirv {
           version: version,
           bound: i[3],
           instructions: instructions,
       })
}

/// Error that can happen when parsing.
#[derive(Debug, Clone)]
pub enum ParseError {
    MissingHeader,
    WrongHeader,
    IncompleteInstruction,
    UnknownConstant(&'static str, u32),
}

#[derive(Debug, Clone)]
pub struct Spirv {
    pub version: (u8, u8),
    pub bound: u32,
    pub instructions: Vec<Instruction>,
}

#[derive(Debug, Clone)]
pub enum Instruction {
    Unknown(u16, Vec<u32>),
    Nop,
    Name { target_id: u32, name: String },
    MemberName {
        target_id: u32,
        member: u32,
        name: String,
    },
    ExtInstImport { result_id: u32, name: String },
    MemoryModel(AddressingModel, MemoryModel),
    EntryPoint {
        execution: ExecutionModel,
        id: u32,
        name: String,
        interface: Vec<u32>,
    },
    ExecutionMode {
        target_id: u32,
        mode: ExecutionMode,
        optional_literals: Vec<u32>,
    },
    Capability(Capability),
    TypeVoid { result_id: u32 },
    TypeBool { result_id: u32 },
    TypeInt {
        result_id: u32,
        width: u32,
        signedness: bool,
    },
    TypeFloat { result_id: u32, width: u32 },
    TypeVector {
        result_id: u32,
        component_id: u32,
        count: u32,
    },
    TypeMatrix {
        result_id: u32,
        column_type_id: u32,
        column_count: u32,
    },
    TypeImage {
        result_id: u32,
        sampled_type_id: u32,
        dim: Dim,
        depth: Option<bool>,
        arrayed: bool,
        ms: bool,
        sampled: Option<bool>,
        format: ImageFormat,
        access: Option<AccessQualifier>,
    },
    TypeSampler { result_id: u32 },
    TypeSampledImage { result_id: u32, image_type_id: u32 },
    TypeArray {
        result_id: u32,
        type_id: u32,
        length_id: u32,
    },
    TypeRuntimeArray { result_id: u32, type_id: u32 },
    TypeStruct {
        result_id: u32,
        member_types: Vec<u32>,
    },
    TypeOpaque { result_id: u32, name: String },
    TypePointer {
        result_id: u32,
        storage_class: StorageClass,
        type_id: u32,
    },
    Constant {
        result_type_id: u32,
        result_id: u32,
        data: Vec<u32>,
    },
    SpecConstantTrue { result_type_id: u32, result_id: u32 },
    SpecConstantFalse { result_type_id: u32, result_id: u32 },
    SpecConstant {
        result_type_id: u32,
        result_id: u32,
        data: Vec<u32>,
    },
    SpecConstantComposite {
        result_type_id: u32,
        result_id: u32,
        data: Vec<u32>,
    },
    FunctionEnd,
    Variable {
        result_type_id: u32,
        result_id: u32,
        storage_class: StorageClass,
        initializer: Option<u32>,
    },
    Decorate {
        target_id: u32,
        decoration: Decoration,
        params: Vec<u32>,
    },
    MemberDecorate {
        target_id: u32,
        member: u32,
        decoration: Decoration,
        params: Vec<u32>,
    },
    Label { result_id: u32 },
    Branch { result_id: u32 },
    Kill,
    Return,
}

fn parse_instruction(i: &[u32]) -> Result<(Instruction, &[u32]), ParseError> {
    assert!(i.len() >= 1);

    let word_count = (i[0] >> 16) as usize;
    assert!(word_count >= 1);
    let opcode = (i[0] & 0xffff) as u16;

    if i.len() < word_count {
        return Err(ParseError::IncompleteInstruction);
    }

    let opcode = decode_instruction(opcode, &i[1 .. word_count])?;
    Ok((opcode, &i[word_count ..]))
}

fn decode_instruction(opcode: u16, operands: &[u32]) -> Result<Instruction, ParseError> {
    Ok(match opcode {
           0 => Instruction::Nop,
           5 => Instruction::Name {
               target_id: operands[0],
               name: parse_string(&operands[1 ..]).0,
           },
           6 => Instruction::MemberName {
               target_id: operands[0],
               member: operands[1],
               name: parse_string(&operands[2 ..]).0,
           },
           11 => Instruction::ExtInstImport {
               result_id: operands[0],
               name: parse_string(&operands[1 ..]).0,
           },
           14 => Instruction::MemoryModel(AddressingModel::from_num(operands[0])?,
                                          MemoryModel::from_num(operands[1])?),
           15 => {
               let (n, r) = parse_string(&operands[2 ..]);
               Instruction::EntryPoint {
                   execution: ExecutionModel::from_num(operands[0])?,
                   id: operands[1],
                   name: n,
                   interface: r.to_owned(),
               }
           },
           16 => {
               Instruction::ExecutionMode {
                   target_id: operands[0],
                   mode: ExecutionMode::from_num(operands[1])?,
                   optional_literals: operands[2 ..].to_vec(),
               }
           },
           17 => Instruction::Capability(Capability::from_num(operands[0])?),
           19 => Instruction::TypeVoid { result_id: operands[0] },
           20 => Instruction::TypeBool { result_id: operands[0] },
           21 => Instruction::TypeInt {
               result_id: operands[0],
               width: operands[1],
               signedness: operands[2] != 0,
           },
           22 => Instruction::TypeFloat {
               result_id: operands[0],
               width: operands[1],
           },
           23 => Instruction::TypeVector {
               result_id: operands[0],
               component_id: operands[1],
               count: operands[2],
           },
           24 => Instruction::TypeMatrix {
               result_id: operands[0],
               column_type_id: operands[1],
               column_count: operands[2],
           },
           25 => Instruction::TypeImage {
               result_id: operands[0],
               sampled_type_id: operands[1],
               dim: Dim::from_num(operands[2])?,
               depth: match operands[3] {
                   0 => Some(false),
                   1 => Some(true),
                   2 => None,
                   _ => unreachable!(),
               },
               arrayed: operands[4] != 0,
               ms: operands[5] != 0,
               sampled: match operands[6] {
                   0 => None,
                   1 => Some(true),
                   2 => Some(false),
                   _ => unreachable!(),
               },
               format: ImageFormat::from_num(operands[7])?,
               access: if operands.len() >= 9 {
                   Some(AccessQualifier::from_num(operands[8])?)
               } else {
                   None
               },
           },
           26 => Instruction::TypeSampler { result_id: operands[0] },
           27 => Instruction::TypeSampledImage {
               result_id: operands[0],
               image_type_id: operands[1],
           },
           28 => Instruction::TypeArray {
               result_id: operands[0],
               type_id: operands[1],
               length_id: operands[2],
           },
           29 => Instruction::TypeRuntimeArray {
               result_id: operands[0],
               type_id: operands[1],
           },
           30 => Instruction::TypeStruct {
               result_id: operands[0],
               member_types: operands[1 ..].to_owned(),
           },
           31 => Instruction::TypeOpaque {
               result_id: operands[0],
               name: parse_string(&operands[1 ..]).0,
           },
           32 => Instruction::TypePointer {
               result_id: operands[0],
               storage_class: StorageClass::from_num(operands[1])?,
               type_id: operands[2],
           },
           43 => Instruction::Constant {
               result_type_id: operands[0],
               result_id: operands[1],
               data: operands[2 ..].to_owned(),
           },
           48 => Instruction::SpecConstantTrue {
               result_type_id: operands[0],
               result_id: operands[1],
           },
           49 => Instruction::SpecConstantFalse {
               result_type_id: operands[0],
               result_id: operands[1],
           },
           50 => Instruction::SpecConstant {
               result_type_id: operands[0],
               result_id: operands[1],
               data: operands[2 ..].to_owned(),
           },
           51 => Instruction::SpecConstantComposite {
               result_type_id: operands[0],
               result_id: operands[1],
               data: operands[2 ..].to_owned(),
           },
           56 => Instruction::FunctionEnd,
           59 => Instruction::Variable {
               result_type_id: operands[0],
               result_id: operands[1],
               storage_class: StorageClass::from_num(operands[2])?,
               initializer: operands.get(3).map(|&v| v),
           },
           71 => Instruction::Decorate {
               target_id: operands[0],
               decoration: Decoration::from_num(operands[1])?,
               params: operands[2 ..].to_owned(),
           },
           72 => Instruction::MemberDecorate {
               target_id: operands[0],
               member: operands[1],
               decoration: Decoration::from_num(operands[2])?,
               params: operands[3 ..].to_owned(),
           },
           248 => Instruction::Label { result_id: operands[0] },
           249 => Instruction::Branch { result_id: operands[0] },
           252 => Instruction::Kill,
           253 => Instruction::Return,
           _ => Instruction::Unknown(opcode, operands.to_owned()),
       })
}

fn parse_string(data: &[u32]) -> (String, &[u32]) {
    let bytes = data.iter()
        .flat_map(|&n| {
                      let b1 = (n & 0xff) as u8;
                      let b2 = ((n >> 8) & 0xff) as u8;
                      let b3 = ((n >> 16) & 0xff) as u8;
                      let b4 = ((n >> 24) & 0xff) as u8;
                      vec![b1, b2, b3, b4].into_iter()
                  })
        .take_while(|&b| b != 0)
        .collect::<Vec<u8>>();

    let r = 1 + bytes.len() / 4;
    let s = String::from_utf8(bytes).expect("Shader content is not UTF-8");

    (s, &data[r ..])
}

#[cfg(test)]
mod test {
    use parse;

    #[test]
    fn test() {
        let data = include_bytes!("../tests/frag.spv");
        println!("{:#?}", parse::parse_spirv(data).unwrap());
    }
}
<commit_msg>Remove pritnln from parse::test::test (#941)<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use enums::*;

/// Parses a SPIR-V document.
pub fn parse_spirv(data: &[u8]) -> Result<Spirv, ParseError> {
    if data.len() < 20 {
        return Err(ParseError::MissingHeader);
    }

    // we need to determine whether we are in big endian order or little endian order depending
    // on the magic number at the start of the file
    let data = if data[0] == 0x07 && data[1] == 0x23 && data[2] == 0x02 && data[3] == 0x03 {
        // big endian
        data.chunks(4)
            .map(|c| {
                     ((c[0] as u32) << 24) | ((c[1] as u32) << 16) | ((c[2] as u32) << 8) |
                         c[3] as u32
                 })
            .collect::<Vec<_>>()

    } else if data[3] == 0x07 && data[2] == 0x23 && data[1] == 0x02 && data[0] == 0x03 {
        // little endian
        data.chunks(4)
            .map(|c| {
                     ((c[3] as u32) << 24) | ((c[2] as u32) << 16) | ((c[1] as u32) << 8) |
                         c[0] as u32
                 })
            .collect::<Vec<_>>()

    } else {
        return Err(ParseError::MissingHeader);
    };

    parse_u32s(&data)
}

/// Parses a SPIR-V document from a list of u32s.
///
/// Endianess has already been handled.
fn parse_u32s(i: &[u32]) -> Result<Spirv, ParseError> {
    if i.len() < 5 {
        return Err(ParseError::MissingHeader);
    }

    if i[0] != 0x07230203 {
        return Err(ParseError::WrongHeader);
    }

    let version = (((i[1] & 0x00ff0000) >> 16) as u8, ((i[1] & 0x0000ff00) >> 8) as u8);

    let instructions = {
        let mut ret = Vec::new();
        let mut i = &i[5 ..];
        while i.len() >= 1 {
            let (instruction, rest) = parse_instruction(i)?;
            ret.push(instruction);
            i = rest;
        }
        ret
    };

    Ok(Spirv {
           version: version,
           bound: i[3],
           instructions: instructions,
       })
}

/// Error that can happen when parsing.
#[derive(Debug, Clone)]
pub enum ParseError {
    MissingHeader,
    WrongHeader,
    IncompleteInstruction,
    UnknownConstant(&'static str, u32),
}

#[derive(Debug, Clone)]
pub struct Spirv {
    pub version: (u8, u8),
    pub bound: u32,
    pub instructions: Vec<Instruction>,
}

#[derive(Debug, Clone)]
pub enum Instruction {
    Unknown(u16, Vec<u32>),
    Nop,
    Name { target_id: u32, name: String },
    MemberName {
        target_id: u32,
        member: u32,
        name: String,
    },
    ExtInstImport { result_id: u32, name: String },
    MemoryModel(AddressingModel, MemoryModel),
    EntryPoint {
        execution: ExecutionModel,
        id: u32,
        name: String,
        interface: Vec<u32>,
    },
    ExecutionMode {
        target_id: u32,
        mode: ExecutionMode,
        optional_literals: Vec<u32>,
    },
    Capability(Capability),
    TypeVoid { result_id: u32 },
    TypeBool { result_id: u32 },
    TypeInt {
        result_id: u32,
        width: u32,
        signedness: bool,
    },
    TypeFloat { result_id: u32, width: u32 },
    TypeVector {
        result_id: u32,
        component_id: u32,
        count: u32,
    },
    TypeMatrix {
        result_id: u32,
        column_type_id: u32,
        column_count: u32,
    },
    TypeImage {
        result_id: u32,
        sampled_type_id: u32,
        dim: Dim,
        depth: Option<bool>,
        arrayed: bool,
        ms: bool,
        sampled: Option<bool>,
        format: ImageFormat,
        access: Option<AccessQualifier>,
    },
    TypeSampler { result_id: u32 },
    TypeSampledImage { result_id: u32, image_type_id: u32 },
    TypeArray {
        result_id: u32,
        type_id: u32,
        length_id: u32,
    },
    TypeRuntimeArray { result_id: u32, type_id: u32 },
    TypeStruct {
        result_id: u32,
        member_types: Vec<u32>,
    },
    TypeOpaque { result_id: u32, name: String },
    TypePointer {
        result_id: u32,
        storage_class: StorageClass,
        type_id: u32,
    },
    Constant {
        result_type_id: u32,
        result_id: u32,
        data: Vec<u32>,
    },
    SpecConstantTrue { result_type_id: u32, result_id: u32 },
    SpecConstantFalse { result_type_id: u32, result_id: u32 },
    SpecConstant {
        result_type_id: u32,
        result_id: u32,
        data: Vec<u32>,
    },
    SpecConstantComposite {
        result_type_id: u32,
        result_id: u32,
        data: Vec<u32>,
    },
    FunctionEnd,
    Variable {
        result_type_id: u32,
        result_id: u32,
        storage_class: StorageClass,
        initializer: Option<u32>,
    },
    Decorate {
        target_id: u32,
        decoration: Decoration,
        params: Vec<u32>,
    },
    MemberDecorate {
        target_id: u32,
        member: u32,
        decoration: Decoration,
        params: Vec<u32>,
    },
    Label { result_id: u32 },
    Branch { result_id: u32 },
    Kill,
    Return,
}

fn parse_instruction(i: &[u32]) -> Result<(Instruction, &[u32]), ParseError> {
    assert!(i.len() >= 1);

    let word_count = (i[0] >> 16) as usize;
    assert!(word_count >= 1);
    let opcode = (i[0] & 0xffff) as u16;

    if i.len() < word_count {
        return Err(ParseError::IncompleteInstruction);
    }

    let opcode = decode_instruction(opcode, &i[1 .. word_count])?;
    Ok((opcode, &i[word_count ..]))
}

fn decode_instruction(opcode: u16, operands: &[u32]) -> Result<Instruction, ParseError> {
    Ok(match opcode {
           0 => Instruction::Nop,
           5 => Instruction::Name {
               target_id: operands[0],
               name: parse_string(&operands[1 ..]).0,
           },
           6 => Instruction::MemberName {
               target_id: operands[0],
               member: operands[1],
               name: parse_string(&operands[2 ..]).0,
           },
           11 => Instruction::ExtInstImport {
               result_id: operands[0],
               name: parse_string(&operands[1 ..]).0,
           },
           14 => Instruction::MemoryModel(AddressingModel::from_num(operands[0])?,
                                          MemoryModel::from_num(operands[1])?),
           15 => {
               let (n, r) = parse_string(&operands[2 ..]);
               Instruction::EntryPoint {
                   execution: ExecutionModel::from_num(operands[0])?,
                   id: operands[1],
                   name: n,
                   interface: r.to_owned(),
               }
           },
           16 => {
               Instruction::ExecutionMode {
                   target_id: operands[0],
                   mode: ExecutionMode::from_num(operands[1])?,
                   optional_literals: operands[2 ..].to_vec(),
               }
           },
           17 => Instruction::Capability(Capability::from_num(operands[0])?),
           19 => Instruction::TypeVoid { result_id: operands[0] },
           20 => Instruction::TypeBool { result_id: operands[0] },
           21 => Instruction::TypeInt {
               result_id: operands[0],
               width: operands[1],
               signedness: operands[2] != 0,
           },
           22 => Instruction::TypeFloat {
               result_id: operands[0],
               width: operands[1],
           },
           23 => Instruction::TypeVector {
               result_id: operands[0],
               component_id: operands[1],
               count: operands[2],
           },
           24 => Instruction::TypeMatrix {
               result_id: operands[0],
               column_type_id: operands[1],
               column_count: operands[2],
           },
           25 => Instruction::TypeImage {
               result_id: operands[0],
               sampled_type_id: operands[1],
               dim: Dim::from_num(operands[2])?,
               depth: match operands[3] {
                   0 => Some(false),
                   1 => Some(true),
                   2 => None,
                   _ => unreachable!(),
               },
               arrayed: operands[4] != 0,
               ms: operands[5] != 0,
               sampled: match operands[6] {
                   0 => None,
                   1 => Some(true),
                   2 => Some(false),
                   _ => unreachable!(),
               },
               format: ImageFormat::from_num(operands[7])?,
               access: if operands.len() >= 9 {
                   Some(AccessQualifier::from_num(operands[8])?)
               } else {
                   None
               },
           },
           26 => Instruction::TypeSampler { result_id: operands[0] },
           27 => Instruction::TypeSampledImage {
               result_id: operands[0],
               image_type_id: operands[1],
           },
           28 => Instruction::TypeArray {
               result_id: operands[0],
               type_id: operands[1],
               length_id: operands[2],
           },
           29 => Instruction::TypeRuntimeArray {
               result_id: operands[0],
               type_id: operands[1],
           },
           30 => Instruction::TypeStruct {
               result_id: operands[0],
               member_types: operands[1 ..].to_owned(),
           },
           31 => Instruction::TypeOpaque {
               result_id: operands[0],
               name: parse_string(&operands[1 ..]).0,
           },
           32 => Instruction::TypePointer {
               result_id: operands[0],
               storage_class: StorageClass::from_num(operands[1])?,
               type_id: operands[2],
           },
           43 => Instruction::Constant {
               result_type_id: operands[0],
               result_id: operands[1],
               data: operands[2 ..].to_owned(),
           },
           48 => Instruction::SpecConstantTrue {
               result_type_id: operands[0],
               result_id: operands[1],
           },
           49 => Instruction::SpecConstantFalse {
               result_type_id: operands[0],
               result_id: operands[1],
           },
           50 => Instruction::SpecConstant {
               result_type_id: operands[0],
               result_id: operands[1],
               data: operands[2 ..].to_owned(),
           },
           51 => Instruction::SpecConstantComposite {
               result_type_id: operands[0],
               result_id: operands[1],
               data: operands[2 ..].to_owned(),
           },
           56 => Instruction::FunctionEnd,
           59 => Instruction::Variable {
               result_type_id: operands[0],
               result_id: operands[1],
               storage_class: StorageClass::from_num(operands[2])?,
               initializer: operands.get(3).map(|&v| v),
           },
           71 => Instruction::Decorate {
               target_id: operands[0],
               decoration: Decoration::from_num(operands[1])?,
               params: operands[2 ..].to_owned(),
           },
           72 => Instruction::MemberDecorate {
               target_id: operands[0],
               member: operands[1],
               decoration: Decoration::from_num(operands[2])?,
               params: operands[3 ..].to_owned(),
           },
           248 => Instruction::Label { result_id: operands[0] },
           249 => Instruction::Branch { result_id: operands[0] },
           252 => Instruction::Kill,
           253 => Instruction::Return,
           _ => Instruction::Unknown(opcode, operands.to_owned()),
       })
}

fn parse_string(data: &[u32]) -> (String, &[u32]) {
    let bytes = data.iter()
        .flat_map(|&n| {
                      let b1 = (n & 0xff) as u8;
                      let b2 = ((n >> 8) & 0xff) as u8;
                      let b3 = ((n >> 16) & 0xff) as u8;
                      let b4 = ((n >> 24) & 0xff) as u8;
                      vec![b1, b2, b3, b4].into_iter()
                  })
        .take_while(|&b| b != 0)
        .collect::<Vec<u8>>();

    let r = 1 + bytes.len() / 4;
    let s = String::from_utf8(bytes).expect("Shader content is not UTF-8");

    (s, &data[r ..])
}

#[cfg(test)]
mod test {
    use parse;

    #[test]
    fn test() {
        let data = include_bytes!("../tests/frag.spv");
        parse::parse_spirv(data).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use xcb;
use cairo::{self, XCBSurface};
use cairo_sys;

use text::Text;

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

// TODO: impl Drop?
pub struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    surface: cairo::Surface,
}

impl Window {
    pub fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface =
            {
                let screen = conn.get_setup()
                    .roots()
                    .nth(screen_idx)
                    .expect("invalid screen");
                let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                              (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

                let (width, height) = (screen.width_in_pixels(), 100);

                xcb::create_window(&conn,
                                   xcb::COPY_FROM_PARENT as u8,
                                   id,
                                   screen.root(),
                                   0,
                                   0,
                                   width,
                                   height,
                                   10,
                                   xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                                   screen.root_visual(),
                                   &values);

                unsafe {
                    let cairo_conn =
                        cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                            *mut cairo_sys::xcb_connection_t);
                    let visual =
                        cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn,
                                                                                &screen)
                                                                         .base as
                                                            *mut xcb::ffi::xcb_visualtype_t as
                                                            *mut cairo_sys::xcb_visualtype_t);
                    let drawable = cairo::XCBDrawable(id);
                    cairo::Surface::create(&cairo_conn,
                                           &drawable,
                                           &visual,
                                           width as i32,
                                           height as i32)
                    // TODO: Update surface width/height when window size changes.
                }
            };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            surface,
        }
    }

    fn screen(&self) -> xcb::Screen {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    pub fn expose(&self, texts: Vec<Text>) {
        self.render_text_blocks(texts);
        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in &mut layouts {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in &mut stretched {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}
<commit_msg>Clear before repainting.<commit_after>use std::rc::Rc;

use xcb;
use cairo::{self, Context, XCBSurface};
use cairo_sys;

use text::{Color, Text};

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

// TODO: impl Drop?
pub struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    surface: cairo::Surface,
}

impl Window {
    pub fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface =
            {
                let screen = conn.get_setup()
                    .roots()
                    .nth(screen_idx)
                    .expect("invalid screen");
                let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                              (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

                let (width, height) = (screen.width_in_pixels(), 100);

                xcb::create_window(&conn,
                                   xcb::COPY_FROM_PARENT as u8,
                                   id,
                                   screen.root(),
                                   0,
                                   0,
                                   width,
                                   height,
                                   10,
                                   xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                                   screen.root_visual(),
                                   &values);

                unsafe {
                    let cairo_conn =
                        cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                            *mut cairo_sys::xcb_connection_t);
                    let visual =
                        cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn,
                                                                                &screen)
                                                                         .base as
                                                            *mut xcb::ffi::xcb_visualtype_t as
                                                            *mut cairo_sys::xcb_visualtype_t);
                    let drawable = cairo::XCBDrawable(id);
                    cairo::Surface::create(&cairo_conn,
                                           &drawable,
                                           &visual,
                                           width as i32,
                                           height as i32)
                    // TODO: Update surface width/height when window size changes.
                }
            };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            surface,
        }
    }

    fn screen(&self) -> xcb::Screen {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    pub fn expose(&self, texts: Vec<Text>) {
        // Clear to black before re-painting.
        let context = Context::new(&self.surface);
        Color::black().apply_to_context(&context);
        context.paint();

        self.render_text_blocks(texts);
        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in &mut layouts {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in &mut stretched {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}
<|endoftext|>


<commit_before>//! Integration tests.

extern crate assert_cmd;
extern crate escargot;
extern crate predicates;
extern crate tempdir;
extern crate utime;

use std::fs::{create_dir_all, File};
use std::io::Write;
use std::process::Command;

use assert_cmd::prelude::*;
use tempdir::TempDir;
use predicates::boolean::PredicateBooleanExt;
use predicates::prelude::predicate::str::{contains, is_empty, similar};

struct TestEnv {
    pub cache_dir: TempDir,
    pub config_dir: TempDir,
    pub input_dir: TempDir,
    pub default_features: bool,
    pub features: Vec<String>,
}

impl TestEnv {
    fn new() -> Self {
        TestEnv {
            cache_dir: TempDir::new(".tldr.test.cache").unwrap(),
            config_dir: TempDir::new(".tldr.test.config").unwrap(),
            input_dir: TempDir::new(".tldr.test.input").unwrap(),
            default_features: true,
            features: vec![],
        }
    }

    /// Add entry for that environment.
    fn add_entry(&self, name: &str, contents: &str) {
        let dir = self.cache_dir.path().join("tldr-master").join("pages").join("common");
        create_dir_all(&dir).unwrap();

        let mut file = File::create(&dir.join(format!("{}.md", name))).unwrap();
        file.write_all(&contents.as_bytes()).unwrap();
    }

    /// Disable default features.
    fn no_default_features(mut self) -> Self {
        self.default_features = false;
        self
    }

    /// Add the specified feature.
    fn with_feature<S: Into<String>>(mut self, feature: S) -> Self {
        self.features.push(feature.into());
        self
    }

    /// Return a new `Command` with env vars set.
    fn command(&self) -> Command {
        let mut build = escargot::CargoBuild::new()
            .bin("tldr")
            .current_release()
            .current_target();
        if !self.default_features {
            build = build.arg("--no-default-features");
        }
        if !self.features.is_empty() {
            build = build.arg(&format!("--feature {}", self.features.join(",")));
        }
        let run = build.run().unwrap();
        let mut cmd = run.command();
        cmd.env("TEALDEER_CACHE_DIR", self.cache_dir.path().to_str().unwrap());
        cmd.env("TEALDEER_CONFIG_DIR", self.config_dir.path().to_str().unwrap());
        cmd
    }
}

#[test]
fn test_missing_cache() {
    TestEnv::new()
        .command()
        .args(&["sl"])
        .assert()
        .failure()
        .stderr(contains("Cache not found. Please run `tldr --update`."));
}

#[test]
fn test_update_cache() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["sl"])
        .assert()
        .failure()
        .stderr(contains("Cache not found. Please run `tldr --update`."));

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    testenv
        .command()
        .args(&["sl"])
        .assert()
        .success();
}

#[test]
fn test_quiet_cache() {
    let testenv = TestEnv::new();
    testenv
        .command()
        .args(&["--update", "--quiet"])
        .assert()
        .success()
        .stdout(is_empty());

    testenv
        .command()
        .args(&["--clear-cache", "--quiet"])
        .assert()
        .success()
        .stdout(is_empty());
}

#[test]
fn test_quiet_failures() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update", "-q"])
        .assert()
        .success()
        .stdout(is_empty());

    testenv
        .command()
        .args(&["fakeprogram", "-q"])
        .assert()
        .failure()
        .stdout(is_empty());
}

#[test]
fn test_quiet_old_cache() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update", "-q"])
        .assert()
        .success()
        .stdout(is_empty());

    let _ = utime::set_file_times(testenv.cache_dir.path().join("tldr-master"), 1, 1).unwrap();

    testenv
        .command()
        .args(&["tldr"])
        .assert()
        .success()
        .stderr(contains("The cache hasn't been updated for more than "));

    testenv
        .command()
        .args(&["tldr", "--quiet"])
        .assert()
        .success()
        .stderr(contains("The cache hasn't been updated for more than ").not());
}

#[test]
fn test_setup_seed_config() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--seed-config"])
        .assert()
        .success()
        .stdout(contains("Successfully created seed config file"));
}

#[test]
fn test_show_config_path() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--config-path"])
        .assert()
        .success()
        .stdout(contains(format!(
            "Config path is: {}",
            testenv.config_dir.path().join("config.toml").to_str().unwrap(),
        )));
}

#[test]
fn test_markdown_rendering() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    let expected = include_str!("tar-markdown.expected");
    testenv
        .command()
        .args(&["-m", "tar"])
        .assert()
        .success()
        .stdout(similar(expected));
}

fn _test_correct_rendering(input_file: &str, filename: &str) {
    let testenv = TestEnv::new();

    // Create input file
    let file_path = testenv.input_dir.path().join(filename);
    println!("Testfile path: {:?}", &file_path);
    let mut file = File::create(&file_path).unwrap();
    file.write_all(input_file.as_bytes()).unwrap();

    let expected = include_str!("inkscape-default.expected");
    testenv
        .command()
        .args(&["-f", &file_path.to_str().unwrap()])
        .assert()
        .success()
        .stdout(similar(expected));
}

/// An end-to-end integration test for direct file rendering (v1 syntax).
#[test]
fn test_correct_rendering_v1() {
    _test_correct_rendering(include_str!("inkscape-v1.md"), "inkscape-v1.md");
}

/// An end-to-end integration test for direct file rendering (v2 syntax).
#[test]
fn test_correct_rendering_v2() {
    _test_correct_rendering(include_str!("inkscape-v2.md"), "inkscape-v2.md");
}

/// An end-to-end integration test for rendering with constom syntax config.
#[test]
fn test_correct_rendering_with_config() {
    let testenv = TestEnv::new();

    // Setup config file
    // TODO should be config::CONFIG_FILE_NAME
    let config_file_path = testenv.config_dir.path().join("config.toml");
    println!("Config path: {:?}", &config_file_path);

    let mut config_file = File::create(&config_file_path).unwrap();
    config_file
        .write(include_str!("config.toml").as_bytes())
        .unwrap();

    // Create input file
    let file_path = testenv.input_dir.path().join("inkscape-v2.md");
    println!("Testfile path: {:?}", &file_path);

    let mut file = File::create(&file_path).unwrap();
    file.write_all(include_str!("inkscape-v2.md").as_bytes()).unwrap();

    // Load expected output
    let expected = include_str!("inkscape-with-config.expected");

    testenv
        .command()
        .args(&["-f", &file_path.to_str().unwrap()])
        .assert()
        .success()
        .stdout(similar(expected));
}

#[test]
fn test_spaces_find_command() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    testenv
        .command()
        .args(&["git", "checkout"])
        .assert()
        .success();
}

#[test]
fn test_pager_flag_enable() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    testenv
        .command()
        .args(&["--pager", "tar"])
        .assert()
        .success();
}

#[test]
fn test_list_flag_rendering() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--list"])
        .assert()
        .failure()
        .stderr(contains("Cache not found. Please run `tldr --update`."));

    testenv.add_entry("foo", "");

    testenv
        .command()
        .args(&["--list"])
        .assert()
        .success()
        .stdout("foo\n");

    testenv.add_entry("bar", "");
    testenv.add_entry("baz", "");
    testenv.add_entry("qux", "");

    testenv
        .command()
        .args(&["--list"])
        .assert()
        .success()
        .stdout("bar\nbaz\nfoo\nqux\n");
}
<commit_msg>Tests: Allow dead code for feature selection (#118)<commit_after>//! Integration tests.

extern crate assert_cmd;
extern crate escargot;
extern crate predicates;
extern crate tempdir;
extern crate utime;

use std::fs::{create_dir_all, File};
use std::io::Write;
use std::process::Command;

use assert_cmd::prelude::*;
use tempdir::TempDir;
use predicates::boolean::PredicateBooleanExt;
use predicates::prelude::predicate::str::{contains, is_empty, similar};

struct TestEnv {
    pub cache_dir: TempDir,
    pub config_dir: TempDir,
    pub input_dir: TempDir,
    pub default_features: bool,
    pub features: Vec<String>,
}

impl TestEnv {
    fn new() -> Self {
        TestEnv {
            cache_dir: TempDir::new(".tldr.test.cache").unwrap(),
            config_dir: TempDir::new(".tldr.test.config").unwrap(),
            input_dir: TempDir::new(".tldr.test.input").unwrap(),
            default_features: true,
            features: vec![],
        }
    }

    /// Add entry for that environment.
    fn add_entry(&self, name: &str, contents: &str) {
        let dir = self.cache_dir.path().join("tldr-master").join("pages").join("common");
        create_dir_all(&dir).unwrap();

        let mut file = File::create(&dir.join(format!("{}.md", name))).unwrap();
        file.write_all(&contents.as_bytes()).unwrap();
    }

    /// Disable default features.
    #[allow(dead_code)] // Might be useful in the future
    fn no_default_features(mut self) -> Self {
        self.default_features = false;
        self
    }

    /// Add the specified feature.
    #[allow(dead_code)] // Might be useful in the future
    fn with_feature<S: Into<String>>(mut self, feature: S) -> Self {
        self.features.push(feature.into());
        self
    }

    /// Return a new `Command` with env vars set.
    fn command(&self) -> Command {
        let mut build = escargot::CargoBuild::new()
            .bin("tldr")
            .current_release()
            .current_target();
        if !self.default_features {
            build = build.arg("--no-default-features");
        }
        if !self.features.is_empty() {
            build = build.arg(&format!("--feature {}", self.features.join(",")));
        }
        let run = build.run().unwrap();
        let mut cmd = run.command();
        cmd.env("TEALDEER_CACHE_DIR", self.cache_dir.path().to_str().unwrap());
        cmd.env("TEALDEER_CONFIG_DIR", self.config_dir.path().to_str().unwrap());
        cmd
    }
}

#[test]
fn test_missing_cache() {
    TestEnv::new()
        .command()
        .args(&["sl"])
        .assert()
        .failure()
        .stderr(contains("Cache not found. Please run `tldr --update`."));
}

#[test]
fn test_update_cache() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["sl"])
        .assert()
        .failure()
        .stderr(contains("Cache not found. Please run `tldr --update`."));

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    testenv
        .command()
        .args(&["sl"])
        .assert()
        .success();
}

#[test]
fn test_quiet_cache() {
    let testenv = TestEnv::new();
    testenv
        .command()
        .args(&["--update", "--quiet"])
        .assert()
        .success()
        .stdout(is_empty());

    testenv
        .command()
        .args(&["--clear-cache", "--quiet"])
        .assert()
        .success()
        .stdout(is_empty());
}

#[test]
fn test_quiet_failures() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update", "-q"])
        .assert()
        .success()
        .stdout(is_empty());

    testenv
        .command()
        .args(&["fakeprogram", "-q"])
        .assert()
        .failure()
        .stdout(is_empty());
}

#[test]
fn test_quiet_old_cache() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update", "-q"])
        .assert()
        .success()
        .stdout(is_empty());

    let _ = utime::set_file_times(testenv.cache_dir.path().join("tldr-master"), 1, 1).unwrap();

    testenv
        .command()
        .args(&["tldr"])
        .assert()
        .success()
        .stderr(contains("The cache hasn't been updated for more than "));

    testenv
        .command()
        .args(&["tldr", "--quiet"])
        .assert()
        .success()
        .stderr(contains("The cache hasn't been updated for more than ").not());
}

#[test]
fn test_setup_seed_config() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--seed-config"])
        .assert()
        .success()
        .stdout(contains("Successfully created seed config file"));
}

#[test]
fn test_show_config_path() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--config-path"])
        .assert()
        .success()
        .stdout(contains(format!(
            "Config path is: {}",
            testenv.config_dir.path().join("config.toml").to_str().unwrap(),
        )));
}

#[test]
fn test_markdown_rendering() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    let expected = include_str!("tar-markdown.expected");
    testenv
        .command()
        .args(&["-m", "tar"])
        .assert()
        .success()
        .stdout(similar(expected));
}

fn _test_correct_rendering(input_file: &str, filename: &str) {
    let testenv = TestEnv::new();

    // Create input file
    let file_path = testenv.input_dir.path().join(filename);
    println!("Testfile path: {:?}", &file_path);
    let mut file = File::create(&file_path).unwrap();
    file.write_all(input_file.as_bytes()).unwrap();

    let expected = include_str!("inkscape-default.expected");
    testenv
        .command()
        .args(&["-f", &file_path.to_str().unwrap()])
        .assert()
        .success()
        .stdout(similar(expected));
}

/// An end-to-end integration test for direct file rendering (v1 syntax).
#[test]
fn test_correct_rendering_v1() {
    _test_correct_rendering(include_str!("inkscape-v1.md"), "inkscape-v1.md");
}

/// An end-to-end integration test for direct file rendering (v2 syntax).
#[test]
fn test_correct_rendering_v2() {
    _test_correct_rendering(include_str!("inkscape-v2.md"), "inkscape-v2.md");
}

/// An end-to-end integration test for rendering with constom syntax config.
#[test]
fn test_correct_rendering_with_config() {
    let testenv = TestEnv::new();

    // Setup config file
    // TODO should be config::CONFIG_FILE_NAME
    let config_file_path = testenv.config_dir.path().join("config.toml");
    println!("Config path: {:?}", &config_file_path);

    let mut config_file = File::create(&config_file_path).unwrap();
    config_file
        .write(include_str!("config.toml").as_bytes())
        .unwrap();

    // Create input file
    let file_path = testenv.input_dir.path().join("inkscape-v2.md");
    println!("Testfile path: {:?}", &file_path);

    let mut file = File::create(&file_path).unwrap();
    file.write_all(include_str!("inkscape-v2.md").as_bytes()).unwrap();

    // Load expected output
    let expected = include_str!("inkscape-with-config.expected");

    testenv
        .command()
        .args(&["-f", &file_path.to_str().unwrap()])
        .assert()
        .success()
        .stdout(similar(expected));
}

#[test]
fn test_spaces_find_command() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    testenv
        .command()
        .args(&["git", "checkout"])
        .assert()
        .success();
}

#[test]
fn test_pager_flag_enable() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--update"])
        .assert()
        .success()
        .stdout(contains("Successfully updated cache."));

    testenv
        .command()
        .args(&["--pager", "tar"])
        .assert()
        .success();
}

#[test]
fn test_list_flag_rendering() {
    let testenv = TestEnv::new();

    testenv
        .command()
        .args(&["--list"])
        .assert()
        .failure()
        .stderr(contains("Cache not found. Please run `tldr --update`."));

    testenv.add_entry("foo", "");

    testenv
        .command()
        .args(&["--list"])
        .assert()
        .success()
        .stdout("foo\n");

    testenv.add_entry("bar", "");
    testenv.add_entry("baz", "");
    testenv.add_entry("qux", "");

    testenv
        .command()
        .args(&["--list"])
        .assert()
        .success()
        .stdout("bar\nbaz\nfoo\nqux\n");
}
<|endoftext|>