<commit_before>use self::parse::{Parser, RawChunk};
use super::{Graph, Node};
use anyhow::{bail, Error};
use std::fmt;

mod parse;

enum Chunk {
    Raw(String),
    Package,
    License,
    Repository,
    Features,
}

pub struct Pattern(Vec<Chunk>);

impl Pattern {
    pub fn new(format: &str) -> Result<Pattern, Error> {
        let mut chunks = vec![];

        for raw in Parser::new(format) {
            let chunk = match raw {
                RawChunk::Text(text) => Chunk::Raw(text.to_owned()),
                RawChunk::Argument("p") => Chunk::Package,
                RawChunk::Argument("l") => Chunk::License,
                RawChunk::Argument("r") => Chunk::Repository,
                RawChunk::Argument("f") => Chunk::Features,
                RawChunk::Argument(a) => {
                    bail!("unsupported pattern `{}`", a);
                }
                RawChunk::Error(err) => bail!("{}", err),
            };
            chunks.push(chunk);
        }

        Ok(Pattern(chunks))
    }

    pub fn display<'a>(&'a self, graph: &'a Graph<'a>, node_index: usize) -> Display<'a> {
        Display {
            pattern: self,
            graph,
            node_index,
        }
    }
}

pub struct Display<'a> {
    pattern: &'a Pattern,
    graph: &'a Graph<'a>,
    node_index: usize,
}

impl<'a> fmt::Display for Display<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let node = self.graph.node(self.node_index);
        match node {
            Node::Package {
                package_id,
                features,
                ..
            } => {
                let package = self.graph.package_for_id(*package_id);
                for chunk in &self.pattern.0 {
                    match chunk {
                        Chunk::Raw(s) => fmt.write_str(s)?,
                        Chunk::Package => {
                            let proc_macro_suffix = if package.proc_macro() {
                                " (proc-macro)"
                            } else {
                                ""
                            };
                            write!(
                                fmt,
                                "{} v{}{}",
                                package.name(),
                                package.version(),
                                proc_macro_suffix
                            )?;

                            let source_id = package.package_id().source_id();
                            if !source_id.is_default_registry() {
                                write!(fmt, " ({})", source_id)?;
                            }
                        }
                        Chunk::License => {
                            if let Some(license) = &package.manifest().metadata().license {
                                write!(fmt, "{}", license)?;
                            }
                        }
                        Chunk::Repository => {
                            if let Some(repository) = &package.manifest().metadata().repository {
                                write!(fmt, "{}", repository)?;
                            }
                        }
                        Chunk::Features => {
                            write!(fmt, "{}", features.join(","))?;
                        }
                    }
                }
            }
            Node::Feature { name, node_index } => {
                let for_node = self.graph.node(*node_index);
                match for_node {
                    Node::Package { package_id, .. } => {
                        write!(fmt, "{} feature \"{}\"", package_id.name(), name)?;
                        if self.graph.is_cli_feature(self.node_index) {
                            write!(fmt, " (command-line)")?;
                        }
                    }
                    // The node_index in Node::Feature must point to a package
                    // node, see `add_feature`.
                    _ => panic!("unexpected feature node {:?}", for_node),
                }
            }
        }

        Ok(())
    }
}
<commit_msg>Add format control character, 'n', for lib_name of lib dependency.<commit_after>use self::parse::{Parser, RawChunk};
use super::{Graph, Node};
use anyhow::{bail, Error};
use std::fmt;

mod parse;

enum Chunk {
    Raw(String),
    Package,
    License,
    Repository,
    Features,
    Name,
}

pub struct Pattern(Vec<Chunk>);

impl Pattern {
    pub fn new(format: &str) -> Result<Pattern, Error> {
        let mut chunks = vec![];

        for raw in Parser::new(format) {
            let chunk = match raw {
                RawChunk::Text(text) => Chunk::Raw(text.to_owned()),
                RawChunk::Argument("p") => Chunk::Package,
                RawChunk::Argument("l") => Chunk::License,
                RawChunk::Argument("r") => Chunk::Repository,
                RawChunk::Argument("f") => Chunk::Features,
                RawChunk::Argument("n") => Chunk::Name,
                RawChunk::Argument(a) => {
                    bail!("unsupported pattern `{}`", a);
                }
                RawChunk::Error(err) => bail!("{}", err),
            };
            chunks.push(chunk);
        }

        Ok(Pattern(chunks))
    }

    pub fn display<'a>(&'a self, graph: &'a Graph<'a>, node_index: usize) -> Display<'a> {
        Display {
            pattern: self,
            graph,
            node_index,
        }
    }
}

pub struct Display<'a> {
    pattern: &'a Pattern,
    graph: &'a Graph<'a>,
    node_index: usize,
}

impl<'a> fmt::Display for Display<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let node = self.graph.node(self.node_index);
        match node {
            Node::Package {
                package_id,
                features,
                ..
            } => {
                let package = self.graph.package_for_id(*package_id);
                for chunk in &self.pattern.0 {
                    match chunk {
                        Chunk::Raw(s) => fmt.write_str(s)?,
                        Chunk::Package => {
                            let proc_macro_suffix = if package.proc_macro() {
                                " (proc-macro)"
                            } else {
                                ""
                            };
                            write!(
                                fmt,
                                "{} v{}{}",
                                package.name(),
                                package.version(),
                                proc_macro_suffix
                            )?;

                            let source_id = package.package_id().source_id();
                            if !source_id.is_default_registry() {
                                write!(fmt, " ({})", source_id)?;
                            }
                        }
                        Chunk::License => {
                            if let Some(license) = &package.manifest().metadata().license {
                                write!(fmt, "{}", license)?;
                            }
                        }
                        Chunk::Repository => {
                            if let Some(repository) = &package.manifest().metadata().repository {
                                write!(fmt, "{}", repository)?;
                            }
                        }
                        Chunk::Features => {
                            write!(fmt, "{}", features.join(","))?;
                        }
                        Chunk::Name => {
                            let pname = package.name().as_str();
                            write!(
                                fmt,
                                "{}",
                                package
                                    .manifest()
                                    .targets()
                                    .iter()
                                    .filter(|t| t.is_dylib() || t.is_lib())
                                    .map(|l| l.name())
                                    .collect::<Vec<_>>()
                                    .get(0)
                                    .unwrap_or(&pname)
                            )?;
                        }
                    }
                }
            }
            Node::Feature { name, node_index } => {
                let for_node = self.graph.node(*node_index);
                match for_node {
                    Node::Package { package_id, .. } => {
                        write!(fmt, "{} feature \"{}\"", package_id.name(), name)?;
                        if self.graph.is_cli_feature(self.node_index) {
                            write!(fmt, " (command-line)")?;
                        }
                    }
                    // The node_index in Node::Feature must point to a package
                    // node, see `add_feature`.
                    _ => panic!("unexpected feature node {:?}", for_node),
                }
            }
        }

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


<commit_before>use libnewsboat::fslock::FsLock;
use std::env;
use std::io::{Error, ErrorKind};
use std::io::{Read, Write};
use std::path::PathBuf;
use std::process::{Command, Stdio};
use tempfile::NamedTempFile;

fn get_exe_dir(exe: &str) -> Result<PathBuf, Error> {
    let mut target_dir = env::current_exe().expect("exe path");
    while target_dir.pop() {
        if target_dir.join(exe).exists() {
            return Ok(target_dir.join(exe));
        }
    }
    Err(Error::new(ErrorKind::NotFound, exe))
}

#[test]
fn t_returns_an_error_if_invalid_lock_location() {
    let tmp = tempfile::tempdir().unwrap();
    let non_existing_dir = tmp.as_ref().join("does-not-exist/");
    let lock_location = non_existing_dir.join("lockfile");

    let mut lock = FsLock::default();
    let mut pid = -1;

    assert!(!lock.try_lock(lock_location.as_ref(), &mut pid));
    assert_eq!(pid, 0);
}

#[test]
fn t_returns_an_error_lock_file_without_write_access() {
    let lock_location = NamedTempFile::new().unwrap();
    let mut perms = lock_location.as_file().metadata().unwrap().permissions();
    perms.set_readonly(true);
    lock_location.as_file().set_permissions(perms).unwrap();

    let mut lock = FsLock::default();
    let mut pid = -1;
    assert!(!lock.try_lock(lock_location.as_ref(), &mut pid));
    assert_eq!(pid, 0);
}

#[test]
fn t_fails_if_lock_was_already_created() {
    let lock_location = NamedTempFile::new().unwrap();

    let target_dir = match env::var("CARGO_BIN_EXE_lock-process") {
        Ok(dir) => dir,
        Err(_) => get_exe_dir("lock-process")
            .unwrap()
            .to_str()
            .unwrap()
            .to_string(),
    };

    let mut child = Command::new(target_dir)
        .arg(lock_location.path())
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();

    let mut lock = FsLock::default();
    let mut pid = 0;
    let cid = child.id() as i32;

    // wait for locked signal
    let stdout = child.stdout.as_mut().unwrap();
    stdout.read(&mut [0]).unwrap();

    assert!(!lock.try_lock(lock_location.as_ref(), &mut pid));
    assert_eq!(pid, cid, "pid should be process holding the lock");

    // notify child to exit and drop lock
    let stdin = child.stdin.as_mut().unwrap();
    stdin.write(b"\n").unwrap();
}

#[test]
fn t_succeeds_if_lock_file_location_is_valid_and_not_locked_by_different_process() {
    let lock_location = NamedTempFile::new().unwrap();
    let mut lock = FsLock::default();
    let mut pid = 0;

    assert!(lock.try_lock(lock_location.as_ref(), &mut pid));
    assert!(lock_location.path().exists());
    assert!(
        lock.try_lock(lock_location.as_ref(), &mut pid),
        "recall succeeds"
    );

    let new_lock_location = NamedTempFile::new().unwrap();

    assert!(lock_location.path().exists());
    assert!(lock.try_lock(new_lock_location.as_ref(), &mut pid));
    assert!(!lock_location.path().exists());
    assert!(new_lock_location.path().exists());
}
<commit_msg>refactor: change helper function name<commit_after>use libnewsboat::fslock::FsLock;
use std::env;
use std::io::{Error, ErrorKind};
use std::io::{Read, Write};
use std::path::PathBuf;
use std::process::{Command, Stdio};
use tempfile::NamedTempFile;

fn get_exe_path(exe: &str) -> Result<PathBuf, Error> {
    let mut p = env::current_exe().expect("exe path");
    while p.pop() {
        if p.join(exe).exists() {
            return Ok(p.join(exe));
        }
    }
    Err(Error::new(ErrorKind::NotFound, exe))
}

#[test]
fn t_returns_an_error_if_invalid_lock_location() {
    let tmp = tempfile::tempdir().unwrap();
    let non_existing_dir = tmp.as_ref().join("does-not-exist/");
    let lock_location = non_existing_dir.join("lockfile");

    let mut lock = FsLock::default();
    let mut pid = -1;

    assert!(!lock.try_lock(lock_location.as_ref(), &mut pid));
    assert_eq!(pid, 0);
}

#[test]
fn t_returns_an_error_lock_file_without_write_access() {
    let lock_location = NamedTempFile::new().unwrap();
    let mut perms = lock_location.as_file().metadata().unwrap().permissions();
    perms.set_readonly(true);
    lock_location.as_file().set_permissions(perms).unwrap();

    let mut lock = FsLock::default();
    let mut pid = -1;
    assert!(!lock.try_lock(lock_location.as_ref(), &mut pid));
    assert_eq!(pid, 0);
}

#[test]
fn t_fails_if_lock_was_already_created() {
    let lock_location = NamedTempFile::new().unwrap();

    let cmd = match env::var("CARGO_BIN_EXE_lock-process") {
        Ok(dir) => dir,
        Err(_) => get_exe_path("lock-process")
            .unwrap()
            .to_str()
            .unwrap()
            .to_string(),
    };

    let mut child = Command::new(cmd)
        .arg(lock_location.path())
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();

    let mut lock = FsLock::default();
    let mut pid = 0;
    let cid = child.id() as i32;

    // wait for locked signal
    let stdout = child.stdout.as_mut().unwrap();
    stdout.read(&mut [0]).unwrap();

    assert!(!lock.try_lock(lock_location.as_ref(), &mut pid));
    assert_eq!(pid, cid, "pid should be process holding the lock");

    // notify child to exit and drop lock
    let stdin = child.stdin.as_mut().unwrap();
    stdin.write(b"\n").unwrap();
}

#[test]
fn t_succeeds_if_lock_file_location_is_valid_and_not_locked_by_different_process() {
    let lock_location = NamedTempFile::new().unwrap();
    let mut lock = FsLock::default();
    let mut pid = 0;

    assert!(lock.try_lock(lock_location.as_ref(), &mut pid));
    assert!(lock_location.path().exists());
    assert!(
        lock.try_lock(lock_location.as_ref(), &mut pid),
        "recall succeeds"
    );

    let new_lock_location = NamedTempFile::new().unwrap();

    assert!(lock_location.path().exists());
    assert!(lock.try_lock(new_lock_location.as_ref(), &mut pid));
    assert!(!lock_location.path().exists());
    assert!(new_lock_location.path().exists());
}
<|endoftext|>


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

//! Operations on ASCII strings and characters.

use to_str::{ToStr,ToStrConsume};
use str;
use cast;

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    // Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!(str::all(~"banana", |c| c.is_ascii()));
        assert!(! str::all(~"ประเทศไทย中华Việt Nam", |c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<commit_msg>Remove re-exports from libcore/core.rc<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Operations on ASCII strings and characters.

use to_str::{ToStr,ToStrConsume};
use str;
use str::StrSlice;
use cast;
use old_iter::BaseIter;
use vec::{CopyableVector, ImmutableVector, OwnedVector};

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    // Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!(str::all(~"banana", |c| c.is_ascii()));
        assert!(! str::all(~"ประเทศไทย中华Việt Nam", |c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<|endoftext|>


<commit_before>use byteorder::{ReadBytesExt, LittleEndian};
use libc::{c_int,size_t,intptr_t};
use std::io::Read;
use std::io;
use std::vec;
use std::ptr;

#[link(name="libfwnt")]
extern {
    fn libfwnt_lzxpress_huffman_decompress(
        compressed_data: *const u8,
        compressed_data_size: size_t,
        uncompressed_data: *mut u8,
        uncompressed_data_size: *mut size_t,
        error: *mut intptr_t
    ) -> c_int;
}

pub fn decompress(compressed_data: &[u8],uncompressed_size: usize) -> Option<Vec<u8>> {
    unsafe {
        // Get size of compressed data
        let compressed_data_size = compressed_data.len() as size_t;

        // Create compressed data pointer
        let compressed_data_ptr = compressed_data.as_ptr();

        let mut uncompressed_data_size: size_t = uncompressed_size;

        // To hold uncompressed data
        let mut uncompressed_data: Vec<u8> = Vec::with_capacity(
            uncompressed_data_size as usize
        );
        let uncompressed_data_ptr = uncompressed_data.as_mut_ptr();

        // Error ptr... not sure if this is how it should be handled...
        let mut error: intptr_t = 0;

        let result: c_int = libfwnt_lzxpress_huffman_decompress(
            compressed_data_ptr,
            compressed_data_size,
            uncompressed_data_ptr,
            &mut uncompressed_data_size,
            &mut error
        );

        if result == 1 {
            uncompressed_data.set_len(
                uncompressed_data_size as usize
            );
            Some(uncompressed_data)
        } else {
            // TODO Handle Errors. -1 == ERROR
            None
        }
    }
}
<commit_msg>removed unused libs<commit_after>use libc::{c_int,size_t,intptr_t};
#[link(name="libfwnt")]
extern {
    fn libfwnt_lzxpress_huffman_decompress(
        compressed_data: *const u8,
        compressed_data_size: size_t,
        uncompressed_data: *mut u8,
        uncompressed_data_size: *mut size_t,
        error: *mut intptr_t
    ) -> c_int;
}

pub fn decompress(compressed_data: &[u8],uncompressed_size: usize) -> Option<Vec<u8>> {
    unsafe {
        // Get size of compressed data
        let compressed_data_size = compressed_data.len() as size_t;

        // Create compressed data pointer
        let compressed_data_ptr = compressed_data.as_ptr();

        let mut uncompressed_data_size: size_t = uncompressed_size;

        // To hold uncompressed data
        let mut uncompressed_data: Vec<u8> = Vec::with_capacity(
            uncompressed_data_size as usize
        );
        let uncompressed_data_ptr = uncompressed_data.as_mut_ptr();

        // Error ptr... not sure if this is how it should be handled...
        let mut error: intptr_t = 0;

        let result: c_int = libfwnt_lzxpress_huffman_decompress(
            compressed_data_ptr,
            compressed_data_size,
            uncompressed_data_ptr,
            &mut uncompressed_data_size,
            &mut error
        );

        if result == 1 {
            uncompressed_data.set_len(
                uncompressed_data_size as usize
            );
            Some(uncompressed_data)
        } else {
            // TODO Handle Errors. -1 == ERROR
            None
        }
    }
}
<|endoftext|>


<commit_before>use compositor::Server;
use wlroots::{key_events::KeyEvent, xkbcommon::xkb::{KEY_Escape, KEY_F1}, CompositorHandle,
              KeyboardHandle, KeyboardHandler, WLR_KEY_PRESSED};
pub struct Keyboard;

impl KeyboardHandler for Keyboard {
    fn on_key(&mut self, compositor: CompositorHandle, keyboard: KeyboardHandle, event: &KeyEvent) {
        with_handles!([(compositor: {compositor})] => {
            if event.key_state() == WLR_KEY_PRESSED {
                for key in event.pressed_keys() {
                    if key == KEY_Escape {
                        compositor.terminate();
                        ::awesome::lua::terminate();
                        // TODO Remove
                    } else if key == KEY_F1 {
                        ::std::thread::spawn(|| {
                            ::std::process::Command::new("weston-terminal").output()
                                .unwrap()
                        });
                    }
                }
            }
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_key(event.time_msec(),
                                         event.keycode(),
                                         event.key_state() as u32);
                seat.keyboard_send_modifiers(&mut keyboard.get_modifier_masks());
            }).expect("Seat was destroyed");
        }).unwrap();
    }
}
<commit_msg>basic meta key detection<commit_after>use compositor::Server;
use wlroots::{key_events::KeyEvent,
              xkbcommon::xkb::{KEY_Escape, KEY_F1, KEY_Super_L, KEY_Super_R}, CompositorHandle,
              KeyboardHandle, KeyboardHandler, WLR_KEY_PRESSED};
pub struct Keyboard;

fn key_is_meta(key: u32) -> bool {
    // TODO configure meta key
    key == KEY_Super_L || key == KEY_Super_R
}

impl KeyboardHandler for Keyboard {
    fn on_key(&mut self, compositor: CompositorHandle, keyboard: KeyboardHandle, event: &KeyEvent) {
        with_handles!([(compositor: {compositor})] => {
            if event.key_state() == WLR_KEY_PRESSED {
                for key in event.pressed_keys() {
                    if key == KEY_Escape {
                        compositor.terminate();
                        ::awesome::lua::terminate();
                        // TODO Remove
                    } else if key == KEY_F1 {
                        ::std::thread::spawn(|| {
                            ::std::process::Command::new("weston-terminal").output()
                                .unwrap()
                        });
                    }
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = true;
                    }
                }
            } else {
                for key in event.pressed_keys() {
                    if key_is_meta(key) {
                        let server: &mut Server = compositor.into();
                        server.seat.meta = false;
                    }
                }
            }
            let server: &mut Server = compositor.into();
            with_handles!([(seat: {&mut server.seat.seat}),
                           (keyboard: {keyboard})] => {
                seat.keyboard_notify_key(event.time_msec(),
                                         event.keycode(),
                                         event.key_state() as u32);
                seat.keyboard_send_modifiers(&mut keyboard.get_modifier_masks());
            }).expect("Seat was destroyed");
        }).unwrap();
    }
}
<|endoftext|>


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

/*!
 * Unicode-intensive `char` methods.
 *
 * These methods implement functionality for `char` that requires knowledge of
 * Unicode definitions, including normalization, categorization, and display information.
 */

use core::option::Option;
use tables::{derived_property, property, general_category, conversions, charwidth};

/// Returns whether the specified `char` is considered a Unicode alphabetic
/// code point
pub fn is_alphabetic(c: char) -> bool   { derived_property::Alphabetic(c) }

/// Returns whether the specified `char` satisfies the 'XID_Start' Unicode property
///
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to ID_Start but modified for closure under NFKx.
#[allow(non_snake_case_functions)]
pub fn is_XID_start(c: char) -> bool    { derived_property::XID_Start(c) }

/// Returns whether the specified `char` satisfies the 'XID_Continue' Unicode property
///
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
#[allow(non_snake_case_functions)]
pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) }

///
/// Indicates whether a `char` is in lower case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Lowercase'.
///
#[inline]
pub fn is_lowercase(c: char) -> bool { derived_property::Lowercase(c) }

///
/// Indicates whether a `char` is in upper case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Uppercase'.
///
#[inline]
pub fn is_uppercase(c: char) -> bool { derived_property::Uppercase(c) }

///
/// Indicates whether a `char` is whitespace
///
/// Whitespace is defined in terms of the Unicode Property 'White_Space'.
///
#[inline]
pub fn is_whitespace(c: char) -> bool {
    // As an optimization ASCII whitespace characters are checked separately
    c == ' '
        || ('\x09' <= c && c <= '\x0d')
        || property::White_Space(c)
}

///
/// Indicates whether a `char` is alphanumeric
///
/// Alphanumericness is defined in terms of the Unicode General Categories
/// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
///
#[inline]
pub fn is_alphanumeric(c: char) -> bool {
    derived_property::Alphabetic(c)
        || general_category::N(c)
}

///
/// Indicates whether a `char` is a control code point
///
/// Control code points are defined in terms of the Unicode General Category
/// 'Cc'.
///
#[inline]
pub fn is_control(c: char) -> bool { general_category::Cc(c) }

/// Indicates whether the `char` is numeric (Nd, Nl, or No)
#[inline]
pub fn is_digit(c: char) -> bool {
    general_category::N(c)
}

/// Convert a char to its uppercase equivalent
///
/// The case-folding performed is the common or simple mapping:
/// it maps one unicode codepoint (one char in Rust) to its uppercase equivalent according
/// to the Unicode database at ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
/// The additional SpecialCasing.txt is not considered here, as it expands to multiple
/// codepoints in some cases.
///
/// A full reference can be found here
/// http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
///
/// # Return value
///
/// Returns the char itself if no conversion was made
#[inline]
pub fn to_uppercase(c: char) -> char {
    conversions::to_upper(c)
}

/// Convert a char to its lowercase equivalent
///
/// The case-folding performed is the common or simple mapping
/// see `to_uppercase` for references and more information
///
/// # Return value
///
/// Returns the char itself if no conversion if possible
#[inline]
pub fn to_lowercase(c: char) -> char {
    conversions::to_lower(c)
}

/// Returns this character's displayed width in columns, or `None` if it is a
/// control character other than `'\x00'`.
///
/// `is_cjk` determines behavior for characters in the Ambiguous category:
/// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
/// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
/// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
/// recommends that these characters be treated as 1 column (i.e.,
/// `is_cjk` = `false`) if the context cannot be reliably determined.
pub fn width(c: char, is_cjk: bool) -> Option<uint> {
    charwidth::width(c, is_cjk)
}

/// Useful functions for Unicode characters.
pub trait UnicodeChar {
    /// Returns whether the specified character is considered a Unicode
    /// alphabetic code point.
    fn is_alphabetic(&self) -> bool;

    /// Returns whether the specified character satisfies the 'XID_Start'
    /// Unicode property.
    ///
    /// 'XID_Start' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to ID_Start but modified for closure under NFKx.
    #[allow(non_snake_case_functions)]
    fn is_XID_start(&self) -> bool;

    /// Returns whether the specified `char` satisfies the 'XID_Continue'
    /// Unicode property.
    ///
    /// 'XID_Continue' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to 'ID_Continue' but modified for closure under NFKx.
    #[allow(non_snake_case_functions)]
    fn is_XID_continue(&self) -> bool;

    /// Indicates whether a character is in lowercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Lowercase`.
    fn is_lowercase(&self) -> bool;

    /// Indicates whether a character is in uppercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Uppercase`.
    fn is_uppercase(&self) -> bool;

    /// Indicates whether a character is whitespace.
    ///
    /// Whitespace is defined in terms of the Unicode Property `White_Space`.
    fn is_whitespace(&self) -> bool;

    /// Indicates whether a character is alphanumeric.
    ///
    /// Alphanumericness is defined in terms of the Unicode General Categories
    /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
    fn is_alphanumeric(&self) -> bool;

    /// Indicates whether a character is a control code point.
    ///
    /// Control code points are defined in terms of the Unicode General
    /// Category `Cc`.
    fn is_control(&self) -> bool;

    /// Indicates whether the character is numeric (Nd, Nl, or No).
    fn is_digit(&self) -> bool;

    /// Converts a character to its lowercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping. See
    /// `to_uppercase()` for references and more information.
    ///
    /// # Return value
    ///
    /// Returns the lowercase equivalent of the character, or the character
    /// itself if no conversion is possible.
    fn to_lowercase(&self) -> char;

    /// Converts a character to its uppercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping: it maps
    /// one unicode codepoint (one character in Rust) to its uppercase
    /// equivalent according to the Unicode database [1]. The additional
    /// `SpecialCasing.txt` is not considered here, as it expands to multiple
    /// codepoints in some cases.
    ///
    /// A full reference can be found here [2].
    ///
    /// # Return value
    ///
    /// Returns the uppercase equivalent of the character, or the character
    /// itself if no conversion was made.
    ///
    /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
    ///
    /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
    fn to_uppercase(&self) -> char;

    /// Returns this character's displayed width in columns, or `None` if it is a
    /// control character other than `'\x00'`.
    ///
    /// `is_cjk` determines behavior for characters in the Ambiguous category:
    /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
    /// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
    /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
    /// recommends that these characters be treated as 1 column (i.e.,
    /// `is_cjk` = `false`) if the context cannot be reliably determined.
    fn width(&self, is_cjk: bool) -> Option<uint>;
}

impl UnicodeChar for char {
    fn is_alphabetic(&self) -> bool { is_alphabetic(*self) }

    fn is_XID_start(&self) -> bool { is_XID_start(*self) }

    fn is_XID_continue(&self) -> bool { is_XID_continue(*self) }

    fn is_lowercase(&self) -> bool { is_lowercase(*self) }

    fn is_uppercase(&self) -> bool { is_uppercase(*self) }

    fn is_whitespace(&self) -> bool { is_whitespace(*self) }

    fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) }

    fn is_control(&self) -> bool { is_control(*self) }

    fn is_digit(&self) -> bool { is_digit(*self) }

    fn to_lowercase(&self) -> char { to_lowercase(*self) }

    fn to_uppercase(&self) -> char { to_uppercase(*self) }

    fn width(&self, is_cjk: bool) -> Option<uint> { width(*self, is_cjk) }
}
<commit_msg>auto merge of #16670 : Swatinem/rust/charascii, r=alexcrichton<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
 * Unicode-intensive `char` methods.
 *
 * These methods implement functionality for `char` that requires knowledge of
 * Unicode definitions, including normalization, categorization, and display information.
 */

use core::option::Option;
use tables::{derived_property, property, general_category, conversions, charwidth};

/// Returns whether the specified `char` is considered a Unicode alphabetic
/// code point
pub fn is_alphabetic(c: char) -> bool {
    match c {
        'a' .. 'z' | 'A' .. 'Z' => true,
        c if c > '\x7f' => derived_property::Alphabetic(c),
        _ => false
    }
}

/// Returns whether the specified `char` satisfies the 'XID_Start' Unicode property
///
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to ID_Start but modified for closure under NFKx.
#[allow(non_snake_case_functions)]
pub fn is_XID_start(c: char) -> bool    { derived_property::XID_Start(c) }

/// Returns whether the specified `char` satisfies the 'XID_Continue' Unicode property
///
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
#[allow(non_snake_case_functions)]
pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) }

///
/// Indicates whether a `char` is in lower case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Lowercase'.
///
#[inline]
pub fn is_lowercase(c: char) -> bool {
    match c {
        'a' .. 'z' => true,
        c if c > '\x7f' => derived_property::Lowercase(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is in upper case
///
/// This is defined according to the terms of the Unicode Derived Core Property 'Uppercase'.
///
#[inline]
pub fn is_uppercase(c: char) -> bool {
    match c {
        'A' .. 'Z' => true,
        c if c > '\x7f' => derived_property::Uppercase(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is whitespace
///
/// Whitespace is defined in terms of the Unicode Property 'White_Space'.
///
#[inline]
pub fn is_whitespace(c: char) -> bool {
    match c {
        ' ' | '\x09' .. '\x0d' => true,
        c if c > '\x7f' => property::White_Space(c),
        _ => false
    }
}

///
/// Indicates whether a `char` is alphanumeric
///
/// Alphanumericness is defined in terms of the Unicode General Categories
/// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
///
#[inline]
pub fn is_alphanumeric(c: char) -> bool {
    is_alphabetic(c)
        || is_digit(c)
}

///
/// Indicates whether a `char` is a control code point
///
/// Control code points are defined in terms of the Unicode General Category
/// 'Cc'.
///
#[inline]
pub fn is_control(c: char) -> bool { general_category::Cc(c) }

/// Indicates whether the `char` is numeric (Nd, Nl, or No)
#[inline]
pub fn is_digit(c: char) -> bool {
    match c {
        '0' .. '9' => true,
        c if c > '\x7f' => general_category::N(c),
        _ => false
    }
}

/// Convert a char to its uppercase equivalent
///
/// The case-folding performed is the common or simple mapping:
/// it maps one unicode codepoint (one char in Rust) to its uppercase equivalent according
/// to the Unicode database at ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
/// The additional SpecialCasing.txt is not considered here, as it expands to multiple
/// codepoints in some cases.
///
/// A full reference can be found here
/// http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
///
/// # Return value
///
/// Returns the char itself if no conversion was made
#[inline]
pub fn to_uppercase(c: char) -> char {
    conversions::to_upper(c)
}

/// Convert a char to its lowercase equivalent
///
/// The case-folding performed is the common or simple mapping
/// see `to_uppercase` for references and more information
///
/// # Return value
///
/// Returns the char itself if no conversion if possible
#[inline]
pub fn to_lowercase(c: char) -> char {
    conversions::to_lower(c)
}

/// Returns this character's displayed width in columns, or `None` if it is a
/// control character other than `'\x00'`.
///
/// `is_cjk` determines behavior for characters in the Ambiguous category:
/// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
/// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
/// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
/// recommends that these characters be treated as 1 column (i.e.,
/// `is_cjk` = `false`) if the context cannot be reliably determined.
pub fn width(c: char, is_cjk: bool) -> Option<uint> {
    charwidth::width(c, is_cjk)
}

/// Useful functions for Unicode characters.
pub trait UnicodeChar {
    /// Returns whether the specified character is considered a Unicode
    /// alphabetic code point.
    fn is_alphabetic(&self) -> bool;

    /// Returns whether the specified character satisfies the 'XID_Start'
    /// Unicode property.
    ///
    /// 'XID_Start' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to ID_Start but modified for closure under NFKx.
    #[allow(non_snake_case_functions)]
    fn is_XID_start(&self) -> bool;

    /// Returns whether the specified `char` satisfies the 'XID_Continue'
    /// Unicode property.
    ///
    /// 'XID_Continue' is a Unicode Derived Property specified in
    /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
    /// mostly similar to 'ID_Continue' but modified for closure under NFKx.
    #[allow(non_snake_case_functions)]
    fn is_XID_continue(&self) -> bool;

    /// Indicates whether a character is in lowercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Lowercase`.
    fn is_lowercase(&self) -> bool;

    /// Indicates whether a character is in uppercase.
    ///
    /// This is defined according to the terms of the Unicode Derived Core
    /// Property `Uppercase`.
    fn is_uppercase(&self) -> bool;

    /// Indicates whether a character is whitespace.
    ///
    /// Whitespace is defined in terms of the Unicode Property `White_Space`.
    fn is_whitespace(&self) -> bool;

    /// Indicates whether a character is alphanumeric.
    ///
    /// Alphanumericness is defined in terms of the Unicode General Categories
    /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
    fn is_alphanumeric(&self) -> bool;

    /// Indicates whether a character is a control code point.
    ///
    /// Control code points are defined in terms of the Unicode General
    /// Category `Cc`.
    fn is_control(&self) -> bool;

    /// Indicates whether the character is numeric (Nd, Nl, or No).
    fn is_digit(&self) -> bool;

    /// Converts a character to its lowercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping. See
    /// `to_uppercase()` for references and more information.
    ///
    /// # Return value
    ///
    /// Returns the lowercase equivalent of the character, or the character
    /// itself if no conversion is possible.
    fn to_lowercase(&self) -> char;

    /// Converts a character to its uppercase equivalent.
    ///
    /// The case-folding performed is the common or simple mapping: it maps
    /// one unicode codepoint (one character in Rust) to its uppercase
    /// equivalent according to the Unicode database [1]. The additional
    /// `SpecialCasing.txt` is not considered here, as it expands to multiple
    /// codepoints in some cases.
    ///
    /// A full reference can be found here [2].
    ///
    /// # Return value
    ///
    /// Returns the uppercase equivalent of the character, or the character
    /// itself if no conversion was made.
    ///
    /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
    ///
    /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
    fn to_uppercase(&self) -> char;

    /// Returns this character's displayed width in columns, or `None` if it is a
    /// control character other than `'\x00'`.
    ///
    /// `is_cjk` determines behavior for characters in the Ambiguous category:
    /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
    /// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
    /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
    /// recommends that these characters be treated as 1 column (i.e.,
    /// `is_cjk` = `false`) if the context cannot be reliably determined.
    fn width(&self, is_cjk: bool) -> Option<uint>;
}

impl UnicodeChar for char {
    fn is_alphabetic(&self) -> bool { is_alphabetic(*self) }

    fn is_XID_start(&self) -> bool { is_XID_start(*self) }

    fn is_XID_continue(&self) -> bool { is_XID_continue(*self) }

    fn is_lowercase(&self) -> bool { is_lowercase(*self) }

    fn is_uppercase(&self) -> bool { is_uppercase(*self) }

    fn is_whitespace(&self) -> bool { is_whitespace(*self) }

    fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) }

    fn is_control(&self) -> bool { is_control(*self) }

    fn is_digit(&self) -> bool { is_digit(*self) }

    fn to_lowercase(&self) -> char { to_lowercase(*self) }

    fn to_uppercase(&self) -> char { to_uppercase(*self) }

    fn width(&self, is_cjk: bool) -> Option<uint> { width(*self, is_cjk) }
}
<|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.

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}
        }
    ) => {
        ordered_passes_renderpass!{
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: []
                }
            ]
        }
    }
}

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:ty,
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]
                }
            ),*
        ]
    ) => {
        use std::vec::IntoIter as VecIntoIter;
        use std::sync::Arc;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::format::ClearValue;
        use $crate::framebuffer::UnsafeRenderPass;
        use $crate::framebuffer::RenderPass;
        use $crate::framebuffer::RenderPassDesc;
        use $crate::framebuffer::RenderPassClearValues;
        use $crate::framebuffer::RenderPassAttachmentsList;
        use $crate::framebuffer::LayoutAttachmentDescription;
        use $crate::framebuffer::LayoutPassDescription;
        use $crate::framebuffer::LayoutPassDependencyDescription;
        use $crate::framebuffer::FramebufferCreationError;
        use $crate::image::Layout;
        use $crate::image::traits::Image;
        use $crate::image::traits::ImageView;

        #[derive(Debug, Clone)]
        pub struct Formats {
            $(
                pub $atch_name: ($format, u32),
            )*
        }

        pub struct CustomRenderPass {
            render_pass: UnsafeRenderPass,
            formats: Formats,
        }

        impl CustomRenderPass {
            pub fn raw(device: &Arc<Device>, formats: &Formats)
                       -> Result<CustomRenderPass, OomError>
            {
                #![allow(unsafe_code)]

                let rp = try!(unsafe {
                    UnsafeRenderPass::raw(device, AttachmentsIter(formats.clone(), 0),
                                          passes(), dependencies())
                });

                Ok(CustomRenderPass {
                    render_pass: rp,
                    formats: formats.clone(),
                })
            }

            #[inline]
            pub fn new(device: &Arc<Device>, formats: &Formats)
                       -> Arc<CustomRenderPass>
            {
                Arc::new(CustomRenderPass::raw(device, formats).unwrap())
            }
        }

        unsafe impl RenderPass for CustomRenderPass {
            #[inline]
            fn render_pass(&self) -> &UnsafeRenderPass {
                &self.render_pass
            }
        }

        unsafe impl RenderPassDesc for CustomRenderPass {
            type AttachmentsIter = AttachmentsIter;
            type PassesIter = VecIntoIter<LayoutPassDescription>;
            type DependenciesIter = VecIntoIter<LayoutPassDependencyDescription>;

            #[inline]
            fn attachments(&self) -> Self::AttachmentsIter {
                AttachmentsIter(self.formats.clone(), 0)
            }

            #[inline]
            fn passes(&self) -> Self::PassesIter {
                passes()
            }

            #[inline]
            fn dependencies(&self) -> Self::DependenciesIter {
                dependencies()
            }
        }

        #[derive(Debug, Clone)]
        pub struct AttachmentsIter(Formats, usize);
        impl ExactSizeIterator for AttachmentsIter {}
        impl Iterator for AttachmentsIter {
            type Item = LayoutAttachmentDescription;

            #[inline]
            fn next(&mut self) -> Option<LayoutAttachmentDescription> {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]

                let mut num = 0;

                $({
                    if self.1 == num {
                        self.1 += 1;

                        let (initial_layout, final_layout) = attachment_layouts(num);

                        return Some($crate::framebuffer::LayoutAttachmentDescription {
                            format: $crate::format::FormatDesc::format(&(self.0).$atch_name.0),
                            samples: (self.0).$atch_name.1,
                            load: $crate::framebuffer::LoadOp::$load,
                            store: $crate::framebuffer::StoreOp::$store,
                            initial_layout: initial_layout,
                            final_layout: final_layout,
                        });
                    }

                    num += 1;
                })*

                None
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                let mut num = 0;
                $(let $atch_name = num; num += 1;)*
                (num, Some(num))
            }
        }

        /// Returns an iterator to the list of passes of this render pass.
        #[inline]
        fn passes() -> VecIntoIter<LayoutPassDescription> {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]

            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            vec![
                $({
                    let mut depth = None;
                    $(
                        depth = Some(($depth_atch, Layout::DepthStencilAttachmentOptimal));
                    )*

                    $crate::framebuffer::LayoutPassDescription {
                        color_attachments: vec![
                            $(
                                ($color_atch, Layout::ColorAttachmentOptimal)
                            ),*
                        ],
                        depth_stencil: depth,
                        input_attachments: vec![
                            $(
                                ($input_atch, Layout::ShaderReadOnlyOptimal)
                            ),*
                        ],
                        resolve_attachments: vec![],
                        preserve_attachments: (0 .. attachment_num).filter(|&a| {
                            $(if a == $color_atch { return false; })*
                            $(if a == $depth_atch { return false; })*
                            $(if a == $input_atch { return false; })*
                            true
                        }).collect()
                    }
                }),*
            ].into_iter()
        }

        /// Returns an iterator to the list of pass dependencies of this render pass.
        #[inline]
        fn dependencies() -> VecIntoIter<LayoutPassDependencyDescription> {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]

            (1 .. passes().len()).flat_map(|p2| {
                (0 .. p2.clone()).map(move |p1| {
                    LayoutPassDependencyDescription {
                        source_subpass: p1,
                        destination_subpass: p2,
                        by_region: false,
                    }
                })
            }).collect::<Vec<_>>().into_iter()
        }

        /// Returns the initial and final layout of an attachment, given its num.
        ///
        /// The value always correspond to the first and last usages of an attachment.
        fn attachment_layouts(num: usize) -> (Layout, Layout) {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]

            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            let mut initial_layout = None;
            let mut final_layout = None;

            $({
                $(
                    if $depth_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::DepthStencilAttachmentOptimal);
                        }
                        final_layout = Some(Layout::DepthStencilAttachmentOptimal);
                    }
                )*

                $(
                    if $color_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ColorAttachmentOptimal);
                        }
                        final_layout = Some(Layout::ColorAttachmentOptimal);
                    }
                )*

                $(
                    if $input_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ShaderReadOnlyOptimal);
                        }
                        final_layout = Some(Layout::ShaderReadOnlyOptimal);
                    }
                )*
            })*

            (initial_layout.unwrap(), final_layout.unwrap())
        }

        #[allow(non_camel_case_types)]
        pub struct AList<'a, $($atch_name: 'a),*> {
            $(
                pub $atch_name: &'a Arc<$atch_name>,
            )*
        }

        #[allow(non_camel_case_types)]
        unsafe impl<'a, $($atch_name: 'static + ImageView),*> RenderPassAttachmentsList<AList<'a, $($atch_name),*>> for CustomRenderPass {
            // TODO: shouldn't build a Vec
            type AttachmentsIter = VecIntoIter<(Arc<ImageView>, Arc<Image>, Layout, Layout)>;

            #[inline]
            fn convert_attachments_list(&self, l: AList<'a, $($atch_name),*>) -> Result<Self::AttachmentsIter, FramebufferCreationError> {
                #![allow(unused_assignments)]

                let mut result = Vec::new();

                let mut num = 0;
                $({
                    if !l.$atch_name.identity_swizzle() {
                        return Err(FramebufferCreationError::AttachmentNotIdentitySwizzled);
                    }

                    // FIXME: lots of checks missing (format, samples, layout, etc.)

                    let (initial_layout, final_layout) = attachment_layouts(num);
                    num += 1;
                    result.push((l.$atch_name.clone() as Arc<_>, ImageView::parent_arc(&l.$atch_name), initial_layout, final_layout));
                })*

                Ok(result.into_iter())
            }
        }

        ordered_passes_renderpass!{__impl_clear_values__ [0] [] [$($atch_name $format, $load,)*] }

        unsafe impl RenderPassClearValues<ClearValues> for CustomRenderPass {
            type ClearValuesIter = ClearValuesIter;

            #[inline]
            fn convert_clear_values(&self, val: ClearValues) -> ClearValuesIter {
                ClearValuesIter(val, 0)
            }
        }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, Clear, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)* $atch_name [$num] $format,] [$($rest)*] }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, $misc:ident, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)*] [$($rest)*] }
    };

    (__impl_clear_values__ [$total:expr] [$($atch:ident [$num:expr] $format:ty,)+] []) => {
        pub struct ClearValues {
            $(
                pub $atch: <$format as $crate::format::FormatDesc>::ClearValue,
            )+
        }

        pub struct ClearValuesIter(ClearValues, usize);

        impl Iterator for ClearValuesIter {
            type Item = $crate::format::ClearValue;

            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                $(
                    if self.1 == $num {
                        self.1 += 1;
                        return Some(ClearValue::from((self.0).$atch));        // FIXME: should use Format::decode_clear_value instead
                    }
                )+

                if self.1 >= $total {
                    None
                } else {
                    Some(ClearValue::None)
                }
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                let len = $total - self.1;
                (len, Some(len))
            }
        }

        impl ExactSizeIterator for ClearValuesIter {}
    };

    (__impl_clear_values__ [$total:expr] [] []) => {
        pub type ClearValues = ();

        pub struct ClearValuesIter((), usize);

        impl Iterator for ClearValuesIter {
            type Item = $crate::format::ClearValue;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> { None }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) { (0, Some(0)) }
        }

        impl ExactSizeIterator for ClearValuesIter {}
    };
}
<commit_msg>Create a custom iterator for render pass passes<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.

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}
        }
    ) => {
        ordered_passes_renderpass!{
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: []
                }
            ]
        }
    }
}

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:ty,
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]
                }
            ),*
        ]
    ) => {
        use std::vec::IntoIter as VecIntoIter;
        use std::sync::Arc;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::format::ClearValue;
        use $crate::framebuffer::UnsafeRenderPass;
        use $crate::framebuffer::RenderPass;
        use $crate::framebuffer::RenderPassDesc;
        use $crate::framebuffer::RenderPassClearValues;
        use $crate::framebuffer::RenderPassAttachmentsList;
        use $crate::framebuffer::LayoutAttachmentDescription;
        use $crate::framebuffer::LayoutPassDescription;
        use $crate::framebuffer::LayoutPassDependencyDescription;
        use $crate::framebuffer::FramebufferCreationError;
        use $crate::image::Layout;
        use $crate::image::traits::Image;
        use $crate::image::traits::ImageView;

        #[derive(Debug, Clone)]
        pub struct Formats {
            $(
                pub $atch_name: ($format, u32),
            )*
        }

        pub struct CustomRenderPass {
            render_pass: UnsafeRenderPass,
            formats: Formats,
        }

        impl CustomRenderPass {
            pub fn raw(device: &Arc<Device>, formats: &Formats)
                       -> Result<CustomRenderPass, OomError>
            {
                #![allow(unsafe_code)]

                let rp = try!(unsafe {
                    UnsafeRenderPass::raw(device, AttachmentsIter(formats.clone(), 0),
                                          PassesIter(0), dependencies())
                });

                Ok(CustomRenderPass {
                    render_pass: rp,
                    formats: formats.clone(),
                })
            }

            #[inline]
            pub fn new(device: &Arc<Device>, formats: &Formats)
                       -> Arc<CustomRenderPass>
            {
                Arc::new(CustomRenderPass::raw(device, formats).unwrap())
            }
        }

        unsafe impl RenderPass for CustomRenderPass {
            #[inline]
            fn render_pass(&self) -> &UnsafeRenderPass {
                &self.render_pass
            }
        }

        unsafe impl RenderPassDesc for CustomRenderPass {
            type AttachmentsIter = AttachmentsIter;
            type PassesIter = PassesIter;
            type DependenciesIter = VecIntoIter<LayoutPassDependencyDescription>;

            #[inline]
            fn attachments(&self) -> Self::AttachmentsIter {
                AttachmentsIter(self.formats.clone(), 0)
            }

            #[inline]
            fn passes(&self) -> Self::PassesIter {
                PassesIter(0)
            }

            #[inline]
            fn dependencies(&self) -> Self::DependenciesIter {
                dependencies()
            }
        }

        #[derive(Debug, Clone)]
        pub struct AttachmentsIter(Formats, usize);
        impl ExactSizeIterator for AttachmentsIter {}
        impl Iterator for AttachmentsIter {
            type Item = LayoutAttachmentDescription;

            #[inline]
            fn next(&mut self) -> Option<LayoutAttachmentDescription> {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]

                let mut num = 0;

                $({
                    if self.1 == num {
                        self.1 += 1;

                        let (initial_layout, final_layout) = attachment_layouts(num);

                        return Some($crate::framebuffer::LayoutAttachmentDescription {
                            format: $crate::format::FormatDesc::format(&(self.0).$atch_name.0),
                            samples: (self.0).$atch_name.1,
                            load: $crate::framebuffer::LoadOp::$load,
                            store: $crate::framebuffer::StoreOp::$store,
                            initial_layout: initial_layout,
                            final_layout: final_layout,
                        });
                    }

                    num += 1;
                })*

                None
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                let mut num = 0;
                $(let $atch_name = num; num += 1;)*
                (num, Some(num))
            }
        }

        #[derive(Debug, Clone)]
        pub struct PassesIter(usize);
        impl ExactSizeIterator for PassesIter {}
        impl Iterator for PassesIter {
            type Item = LayoutPassDescription;

            #[inline]
            fn next(&mut self) -> Option<LayoutPassDescription> {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]

                let mut attachment_num = 0;
                $(
                    let $atch_name = attachment_num;
                    attachment_num += 1;
                )*

                let mut cur_pass_num = 0;

                $({
                    if self.0 == cur_pass_num {
                        self.0 += 1;

                        let mut depth = None;
                        $(
                            depth = Some(($depth_atch, Layout::DepthStencilAttachmentOptimal));
                        )*

                        return Some(LayoutPassDescription {
                            color_attachments: vec![
                                $(
                                    ($color_atch, Layout::ColorAttachmentOptimal)
                                ),*
                            ],
                            depth_stencil: depth,
                            input_attachments: vec![
                                $(
                                    ($input_atch, Layout::ShaderReadOnlyOptimal)
                                ),*
                            ],
                            resolve_attachments: vec![],
                            preserve_attachments: (0 .. attachment_num).filter(|&a| {
                                $(if a == $color_atch { return false; })*
                                $(if a == $depth_atch { return false; })*
                                $(if a == $input_atch { return false; })*
                                true
                            }).collect()
                        });
                    }

                    cur_pass_num += 1;
                }),*

                None
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                let mut num = 0;
                $($(let $color_atch = num;)* num += 1;)*
                (num, Some(num))
            }
        }

        /// Returns an iterator to the list of pass dependencies of this render pass.
        #[inline]
        fn dependencies() -> VecIntoIter<LayoutPassDependencyDescription> {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]

            (1 .. PassesIter(0).len()).flat_map(|p2| {
                (0 .. p2.clone()).map(move |p1| {
                    LayoutPassDependencyDescription {
                        source_subpass: p1,
                        destination_subpass: p2,
                        by_region: false,
                    }
                })
            }).collect::<Vec<_>>().into_iter()
        }

        /// Returns the initial and final layout of an attachment, given its num.
        ///
        /// The value always correspond to the first and last usages of an attachment.
        fn attachment_layouts(num: usize) -> (Layout, Layout) {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]

            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            let mut initial_layout = None;
            let mut final_layout = None;

            $({
                $(
                    if $depth_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::DepthStencilAttachmentOptimal);
                        }
                        final_layout = Some(Layout::DepthStencilAttachmentOptimal);
                    }
                )*

                $(
                    if $color_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ColorAttachmentOptimal);
                        }
                        final_layout = Some(Layout::ColorAttachmentOptimal);
                    }
                )*

                $(
                    if $input_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ShaderReadOnlyOptimal);
                        }
                        final_layout = Some(Layout::ShaderReadOnlyOptimal);
                    }
                )*
            })*

            (initial_layout.unwrap(), final_layout.unwrap())
        }

        #[allow(non_camel_case_types)]
        pub struct AList<'a, $($atch_name: 'a),*> {
            $(
                pub $atch_name: &'a Arc<$atch_name>,
            )*
        }

        #[allow(non_camel_case_types)]
        unsafe impl<'a, $($atch_name: 'static + ImageView),*> RenderPassAttachmentsList<AList<'a, $($atch_name),*>> for CustomRenderPass {
            // TODO: shouldn't build a Vec
            type AttachmentsIter = VecIntoIter<(Arc<ImageView>, Arc<Image>, Layout, Layout)>;

            #[inline]
            fn convert_attachments_list(&self, l: AList<'a, $($atch_name),*>) -> Result<Self::AttachmentsIter, FramebufferCreationError> {
                #![allow(unused_assignments)]

                let mut result = Vec::new();

                let mut num = 0;
                $({
                    if !l.$atch_name.identity_swizzle() {
                        return Err(FramebufferCreationError::AttachmentNotIdentitySwizzled);
                    }

                    // FIXME: lots of checks missing (format, samples, layout, etc.)

                    let (initial_layout, final_layout) = attachment_layouts(num);
                    num += 1;
                    result.push((l.$atch_name.clone() as Arc<_>, ImageView::parent_arc(&l.$atch_name), initial_layout, final_layout));
                })*

                Ok(result.into_iter())
            }
        }

        ordered_passes_renderpass!{__impl_clear_values__ [0] [] [$($atch_name $format, $load,)*] }

        unsafe impl RenderPassClearValues<ClearValues> for CustomRenderPass {
            type ClearValuesIter = ClearValuesIter;

            #[inline]
            fn convert_clear_values(&self, val: ClearValues) -> ClearValuesIter {
                ClearValuesIter(val, 0)
            }
        }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, Clear, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)* $atch_name [$num] $format,] [$($rest)*] }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, $misc:ident, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)*] [$($rest)*] }
    };

    (__impl_clear_values__ [$total:expr] [$($atch:ident [$num:expr] $format:ty,)+] []) => {
        pub struct ClearValues {
            $(
                pub $atch: <$format as $crate::format::FormatDesc>::ClearValue,
            )+
        }

        pub struct ClearValuesIter(ClearValues, usize);

        impl Iterator for ClearValuesIter {
            type Item = $crate::format::ClearValue;

            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                $(
                    if self.1 == $num {
                        self.1 += 1;
                        return Some(ClearValue::from((self.0).$atch));        // FIXME: should use Format::decode_clear_value instead
                    }
                )+

                if self.1 >= $total {
                    None
                } else {
                    Some(ClearValue::None)
                }
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                let len = $total - self.1;
                (len, Some(len))
            }
        }

        impl ExactSizeIterator for ClearValuesIter {}
    };

    (__impl_clear_values__ [$total:expr] [] []) => {
        pub type ClearValues = ();

        pub struct ClearValuesIter((), usize);

        impl Iterator for ClearValuesIter {
            type Item = $crate::format::ClearValue;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> { None }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) { (0, Some(0)) }
        }

        impl ExactSizeIterator for ClearValuesIter {}
    };
}
<|endoftext|>