<commit_before>#[derive(Debug, Clone)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug, Clone)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug, Clone)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

type ReTr<'a> = Result<&'a mut Tree, String>;

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> ReTr {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn look_up_father(&mut self, v: &i32) -> (ReTr, String) {
        let mut this: &mut Self = self;
        loop {
            if *v == this.right.as_ref().unwrap().enter.val {
                return (Ok(this), "right".to_string());
            } else if *v == this.left.as_ref().unwrap().enter.val {
                return (Ok(this), "left".to_string());
            } else if *v > this.enter.val {
                if let None = this.right {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn cut_left_tree(&mut self) -> Box<Self> {
        self.left.clone().unwrap()
    }

    fn cut_right_tree(&mut self) -> Box<Self> {
        self.right.clone().unwrap()
    }

    fn left_shift(&mut self, v: &i32) {
        let father = self.look_up_father(v).0.unwrap();
        let mut this = father.cut_left_tree();
        let mut son = this.cut_right_tree();
        let grand_son = son.cut_left_tree();

        this.right = Some(grand_son);
        son.left = Some(this);
        father.left = Some(son);
    }
}

fn main() {
    //let mut a = Tree::new(&3);
    //a.insert(&2);
    //a.insert(&1);
    //a.insert(&4);
    //a.insert(&5);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    //println!("{:?}", a.look_up_father(&4));
    //println!("{:?}", a);

    let mut b = Tree::new(&10);
    b.insert(&2);
    b.insert(&1);
    b.insert(&5);
    b.insert(&3);
    b.insert(&6);
    b.insert(&11);

    //println!("{:?}", b);
    //println!("{:?}", b.look_up_father(&2));
    b.left_shift(&2);
    println!("{:?}", b);
}
<commit_msg>add right shift<commit_after>#[derive(Debug, Clone)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug, Clone)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug, Clone)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

type ReTr<'a> = Result<&'a mut Tree, String>;

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> ReTr {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn look_up_father(&mut self, v: &i32) -> (ReTr, String) {
        let mut this: &mut Self = self;
        loop {
            if *v == this.right.as_ref().unwrap().enter.val {
                return (Ok(this), "right".to_string());
            } else if *v == this.left.as_ref().unwrap().enter.val {
                return (Ok(this), "left".to_string());
            } else if *v > this.enter.val {
                if let None = this.right {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn cut_left_tree(&mut self) -> Option<Box<Self>> {
        self.left.clone()
    }

    fn cut_right_tree(&mut self) -> Option<Box<Self>> {
        self.right.clone()
    }

    fn left_shift(&mut self, v: &i32) {
        let father = self.look_up_father(v).0.unwrap();
        let mut this = father.cut_left_tree().unwrap();
        let mut son = this.cut_right_tree().unwrap();
        let grand_son = son.cut_left_tree().unwrap();

        this.right = Some(grand_son);
        son.left = Some(this);
        father.left = Some(son);
    }

    fn right_shift(&mut self, v: &i32) {
        let father = self.look_up_father(v).0.unwrap();
        let mut this = father.cut_right_tree().unwrap();
        let mut son = this.cut_left_tree().unwrap();
        let grand_son = son.cut_right_tree().unwrap();

        this.left = Some(grand_son);
        son.right = Some(this);
        father.right = Some(son);
    }
}

fn main() {
    //let mut a = Tree::new(&3);
    //a.insert(&2);
    //a.insert(&1);
    //a.insert(&4);
    //a.insert(&5);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    //println!("{:?}", a.look_up_father(&4));
    //println!("{:?}", a);

    //let mut b = Tree::new(&10);
    //b.insert(&2);
    //b.insert(&1);
    //b.insert(&5);
    //b.insert(&3);
    //b.insert(&6);
    //b.insert(&11);

    //println!("{:?}", b);
    //println!("{:?}", b.look_up_father(&2));
    //b.left_shift(&2);
    //println!("{:?}", b);

    let mut c = Tree::new(&2);
    c.insert(&8);
    c.insert(&1);
    c.insert(&5);
    c.insert(&4);
    c.insert(&7);
    c.insert(&9);
    //println!("{:?}", c.look_up_father(&8));
    c.right_shift(&8);
    println!("{:?}", c);
}
<|endoftext|>


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

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("pc-windows") {
        let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let mut lib_dir = manifest_dir.clone();
        let mut dll_dir = manifest_dir.clone();
        if target.contains("msvc") {
            lib_dir.push("msvc");
            dll_dir.push("msvc");
        }
        else {
            lib_dir.push("gnu-mingw");
            dll_dir.push("gnu-mingw");
        }
        lib_dir.push("lib");
        dll_dir.push("lib");
        if target.contains("x86_64") {
            lib_dir.push("x64");
            dll_dir.push("x64");
        }
        else {
            lib_dir.push("x64");
            dll_dir.push("x86");
        }
        println!("cargo:rustc-link-search=all={}", lib_dir.display());
        for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir")  {
            let entry_path = entry.expect("Invalid fs entry").path();
            let file_name_result = entry_path.file_name();
            let mut new_file_path = manifest_dir.clone();
            if let Some(file_name) = file_name_result {
                let file_name = file_name.to_str().unwrap();
                if file_name.ends_with(".dll") {
                    new_file_path.push(file_name);
                    std::fs::copy(&entry_path, new_file_path.as_path()).expect("Can't copy from DLL dir");
                }
            }
        }
    }
}<commit_msg>Wow, it works<commit_after>use std::env;
use std::path::PathBuf;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("pc-windows") {
        let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let mut lib_dir = manifest_dir.clone();
        let mut dll_dir = manifest_dir.clone();
        if target.contains("msvc") {
            lib_dir.push("msvc");
            dll_dir.push("msvc");
        }
        else {
            lib_dir.push("gnu-mingw");
            dll_dir.push("gnu-mingw");
        }
        lib_dir.push("lib");
        dll_dir.push("lib");
        if target.contains("x86_64") {
            lib_dir.push("x64");
            dll_dir.push("x64");
        }
        else {
            lib_dir.push("x86");
            dll_dir.push("x86");
        }
        println!("cargo:rustc-link-search=all={}", lib_dir.display());
        for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir")  {
            let entry_path = entry.expect("Invalid fs entry").path();
            let file_name_result = entry_path.file_name();
            let mut new_file_path = manifest_dir.clone();
            if let Some(file_name) = file_name_result {
                let file_name = file_name.to_str().unwrap();
                if file_name.ends_with(".dll") {
                    new_file_path.push(file_name);
                    std::fs::copy(&entry_path, new_file_path.as_path()).expect("Can't copy from DLL dir");
                }
            }
        }
    }
}<|endoftext|>


<commit_before>use std::io::Command;
use std::os;

fn main() {
    let curr_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    Command::new("git").arg("submodule").arg("update").arg("--init").cwd(&curr_dir).status().unwrap();

    let nvim_dir = curr_dir.join("neovim");
    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "src", "nvim"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<commit_msg>Update neovim and build script<commit_after>use std::io::Command;
use std::os;

fn main() {
    let curr_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    Command::new("git").arg("submodule").arg("update").arg("--init").cwd(&curr_dir).status().unwrap();

    let nvim_dir = curr_dir.join("neovim");
    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "lib"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<|endoftext|>


<commit_before>fn main() {
    manage_docs();
}

#[cfg(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs"))]
fn manage_docs () {
    extern crate lgpl_docs;
    const PATH: &'static str = "src";
    const IGNORES: &'static [&'static str] = &[
        "lib.rs",
        "prelude.rs",
        "rt.rs",
        "signal.rs",
    ];
    lgpl_docs::purge(PATH, IGNORES);
    if cfg!(feature = "embed-lgpl-docs") {
        lgpl_docs::embed(lgpl_docs::GTK_DOCS, PATH, IGNORES);
    }
}

#[cfg(not(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs")))]
fn manage_docs() { }
<commit_msg>lgpl-docs API update<commit_after>fn main() {
    manage_docs();
}

#[cfg(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs"))]
fn manage_docs () {
    extern crate lgpl_docs;
    const PATH: &'static str = "src";
    const IGNORES: &'static [&'static str] = &[
        "lib.rs",
        "prelude.rs",
        "rt.rs",
        "signal.rs",
    ];
    lgpl_docs::purge(PATH, IGNORES);
    if cfg!(feature = "embed-lgpl-docs") {
        lgpl_docs::embed(lgpl_docs::Library::Gtk, PATH, IGNORES);
    }
}

#[cfg(not(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs")))]
fn manage_docs() { }
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let out_dir = env::var("OUT_DIR")?;
    let out_dir = Path::new(&out_dir);
    let src_dir = Path::new("data");

    generate(
        src_dir.join("adjectives.txt"),
        out_dir.join("adjectives.rs"),
    )?;
    generate(src_dir.join("nouns.txt"), out_dir.join("nouns.rs"))?;
    Ok(())
}

fn generate(src_path: impl AsRef<Path>, dst_path: impl AsRef<Path>) -> io::Result<()> {
    let src = BufReader::new(File::open(src_path.as_ref())?);
    let mut dst = BufWriter::new(File::create(dst_path.as_ref())?);

    writeln!(dst, "[")?;
    for word in src.lines() {
        writeln!(dst, "\"{}\",", &word.unwrap())?;
    }
    writeln!(dst, "]")
}
<commit_msg>chore(release): update version if a nightly build<commit_after>use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    update_version_if_nightly();

    let out_dir = env::var("OUT_DIR")?;
    let out_dir = Path::new(&out_dir);
    let src_dir = Path::new("data");

    generate(
        src_dir.join("adjectives.txt"),
        out_dir.join("adjectives.rs"),
    )?;
    generate(src_dir.join("nouns.txt"), out_dir.join("nouns.rs"))?;
    Ok(())
}

fn generate(src_path: impl AsRef<Path>, dst_path: impl AsRef<Path>) -> io::Result<()> {
    let src = BufReader::new(File::open(src_path.as_ref())?);
    let mut dst = BufWriter::new(File::create(dst_path.as_ref())?);

    writeln!(dst, "[")?;
    for word in src.lines() {
        writeln!(dst, "\"{}\",", &word.unwrap())?;
    }
    writeln!(dst, "]")
}

fn update_version_if_nightly() {
    println!("cargo:rerun-if-env-changed=NIGHTLY_BUILD");
    if let Ok(date) = std::env::var("NIGHTLY_BUILD") {
        println!(
            "cargo:rustc-env=CARGO_PKG_VERSION={}-nightly.{}",
            std::env::var("CARGO_PKG_VERSION")
                .unwrap()
                .split('-')
                .next()
                .unwrap(),
            date,
        );
    }
}
<|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.

//! Buffer whose content is accessible to the CPU.
//!
//! The `CpuAccessibleBuffer` is a basic general-purpose buffer. It can be used in any situation
//! but may not perform as well as other buffer types.
//!
//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
//! You can read the buffer multiple times simultaneously. Trying to read and write simultaneously,
//! or write and write simultaneously will block.

use smallvec::SmallVec;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr;
use std::sync::Arc;
use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use std::sync::RwLockWriteGuard;
use std::sync::TryLockError;

use buffer::BufferUsage;
use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::TypedBufferAccess;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use instance::QueueFamily;
use memory::Content;
use memory::CpuAccess as MemCpuAccess;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::Sharing;

use OomError;

/// Buffer whose content is accessible by the CPU.
#[derive(Debug)]
pub struct CpuAccessibleBuffer<T: ?Sized, A = Arc<StdMemoryPool>>
    where A: MemoryPool
{
    // Inner content.
    inner: UnsafeBuffer,

    // The memory held by the buffer.
    memory: A::Alloc,

    // Access pattern of the buffer. Can be read-locked for a shared CPU access, or write-locked
    // for either a write CPU access or a GPU access.
    access: RwLock<()>,

    // Queue families allowed to access this buffer.
    queue_families: SmallVec<[u32; 4]>,

    // Necessary to make it compile.
    marker: PhantomData<Box<T>>,
}

impl<T> CpuAccessibleBuffer<T> {
    /// Deprecated. Use `from_data` instead.
    #[deprecated]
    #[inline]
    pub fn new<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
                      -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe { CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families) }
    }

    /// Builds a new buffer with some data in it. Only allowed for sized data.
    pub fn from_data<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I, data: T)
                            -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>,
              T: Content + 'static
    {
        unsafe {
            let uninitialized =
                CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)?;

            // Note that we are in panic-unsafety land here. However a panic should never ever
            // happen here, so in theory we are safe.
            // TODO: check whether that's true ^

            {
                let mut mapping = uninitialized.write().unwrap();
                ptr::write::<T>(&mut *mapping, data)
            }

            Ok(uninitialized)
        }
    }

    /// Builds a new uninitialized buffer. Only allowed for sized data.
    #[inline]
    pub unsafe fn uninitialized<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
                                       -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
    }
}

impl<T> CpuAccessibleBuffer<[T]> {
    /// Builds a new buffer that contains an array `T`. The initial data comes from an iterator
    /// that produces that list of Ts.
    pub fn from_iter<'a, I, Q>(device: Arc<Device>, usage: BufferUsage, queue_families: Q, data: I)
                               -> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
        where I: ExactSizeIterator<Item = T>,
              T: Content + 'static,
              Q: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            let uninitialized = CpuAccessibleBuffer::uninitialized_array(device,
                                                                         data.len(),
                                                                         usage,
                                                                         queue_families)?;

            // Note that we are in panic-unsafety land here. However a panic should never ever
            // happen here, so in theory we are safe.
            // TODO: check whether that's true ^

            {
                let mut mapping = uninitialized.write().unwrap();

                for (i, o) in data.zip(mapping.iter_mut()) {
                    ptr::write(o, i);
                }
            }

            Ok(uninitialized)
        }
    }

    /// Deprecated. Use `uninitialized_array` or `from_iter` instead.
    // TODO: remove
    #[inline]
    #[deprecated]
    pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage, queue_families: I)
                        -> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe { CpuAccessibleBuffer::uninitialized_array(device, len, usage, queue_families) }
    }

    /// Builds a new buffer. Can be used for arrays.
    #[inline]
    pub unsafe fn uninitialized_array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage,
                                             queue_families: I)
                                             -> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        CpuAccessibleBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
    }
}

impl<T: ?Sized> CpuAccessibleBuffer<T> {
    /// Builds a new buffer without checking the size.
    ///
    /// # Safety
    ///
    /// You must ensure that the size that you pass is correct for `T`.
    ///
    pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage,
                             queue_families: I)
                             -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        let queue_families = queue_families
            .into_iter()
            .map(|f| f.id())
            .collect::<SmallVec<[u32; 4]>>();

        let (buffer, mem_reqs) = {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            match UnsafeBuffer::new(device.clone(), size, usage, sharing, SparseLevel::none()) {
                Ok(b) => b,
                Err(BufferCreationError::OomError(err)) => return Err(err),
                Err(_) => unreachable!(),        // We don't use sparse binding, therefore the other
                // errors can't happen
            }
        };

        let mem_ty = device
            .physical_device()
            .memory_types()
            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
            .filter(|t| t.is_host_visible())
            .next()
            .unwrap(); // Vk specs guarantee that this can't fail

        let mem = MemoryPool::alloc(&Device::standard_pool(&device),
                                    mem_ty,
                                    mem_reqs.size,
                                    mem_reqs.alignment,
                                    AllocLayout::Linear)?;
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        debug_assert!(mem.mapped_memory().is_some());
        buffer.bind_memory(mem.memory(), mem.offset())?;

        Ok(Arc::new(CpuAccessibleBuffer {
                        inner: buffer,
                        memory: mem,
                        access: RwLock::new(()),
                        queue_families: queue_families,
                        marker: PhantomData,
                    }))
    }
}

impl<T: ?Sized, A> CpuAccessibleBuffer<T, A>
    where A: MemoryPool
{
    /// Returns the device used to create this buffer.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }

    /// Returns the queue families this buffer can be used on.
    // TODO: use a custom iterator
    #[inline]
    pub fn queue_families(&self) -> Vec<QueueFamily> {
        self.queue_families
            .iter()
            .map(|&num| {
                     self.device()
                         .physical_device()
                         .queue_family_by_id(num)
                         .unwrap()
                 })
            .collect()
    }
}

impl<T: ?Sized, A> CpuAccessibleBuffer<T, A>
    where T: Content + 'static,
          A: MemoryPool
{
    /// Locks the buffer in order to write its content.
    ///
    /// If the buffer is currently in use by the GPU, this function will block until either the
    /// buffer is available or the timeout is reached. A value of `0` for the timeout is valid and
    /// means that the function should never block.
    ///
    /// After this function successfully locks the buffer, any attempt to submit a command buffer
    /// that uses it will block until you unlock it.
    #[inline]
    pub fn read(&self) -> Result<ReadLock<T>, TryLockError<RwLockReadGuard<()>>> {
        let lock = self.access.try_read()?;

        let offset = self.memory.offset();
        let range = offset .. offset + self.inner.size();

        Ok(ReadLock {
               inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
               lock: lock,
           })
    }

    /// Locks the buffer in order to write its content.
    ///
    /// If the buffer is currently in use by the GPU, this function will block until either the
    /// buffer is available or the timeout is reached. A value of `0` for the timeout is valid and
    /// means that the function should never block.
    ///
    /// After this function successfully locks the buffer, any attempt to submit a command buffer
    /// that uses it will block until you unlock it.
    #[inline]
    pub fn write(&self) -> Result<WriteLock<T>, TryLockError<RwLockWriteGuard<()>>> {
        let lock = self.access.try_write()?;

        let offset = self.memory.offset();
        let range = offset .. offset + self.inner.size();

        Ok(WriteLock {
               inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
               lock: lock,
           })
    }
}

unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
    where T: 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn inner(&self) -> BufferInner {
        BufferInner {
            buffer: &self.inner,
            offset: 0,
        }
    }

    #[inline]
    fn size(&self) -> usize {
        self.inner.size()
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        self.inner.key()
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
        Ok(()) // FIXME:
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        // FIXME:
    }

    #[inline]
    unsafe fn unlock(&self) {
        // TODO:
    }
}

unsafe impl<T: ?Sized, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
    where T: 'static + Send + Sync,
          A: MemoryPool
{
    type Content = T;
}

unsafe impl<T: ?Sized, A> DeviceOwned for CpuAccessibleBuffer<T, A>
    where A: MemoryPool
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }
}

pub struct CpuAccessibleBufferClState {
    size: usize,
    stages: PipelineStages,
    access: AccessFlagBits,
    first_stages: Option<PipelineStages>,
    write: bool,
    earliest_previous_transition: usize,
    needs_flush_at_the_end: bool,
}

pub struct CpuAccessibleBufferFinished {
    first_stages: PipelineStages,
    write: bool,
}

/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
///
/// Note that this object holds a rwlock read guard on the chunk. If another thread tries to access
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
pub struct ReadLock<'a, T: ?Sized + 'a> {
    inner: MemCpuAccess<'a, T>,
    lock: RwLockReadGuard<'a, ()>,
}

impl<'a, T: ?Sized + 'a> ReadLock<'a, T> {
    /// Makes a new `ReadLock` to access a sub-part of the current `ReadLock`.
    #[inline]
    pub fn map<U: ?Sized + 'a, F>(self, f: F) -> ReadLock<'a, U>
        where F: FnOnce(&mut T) -> &mut U
    {
        ReadLock {
            inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
            lock: self.lock,
        }
    }
}

impl<'a, T: ?Sized + 'a> Deref for ReadLock<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.inner.deref()
    }
}

/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
///
/// Note that this object holds a rwlock write guard on the chunk. If another thread tries to access
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
pub struct WriteLock<'a, T: ?Sized + 'a> {
    inner: MemCpuAccess<'a, T>,
    lock: RwLockWriteGuard<'a, ()>,
}

impl<'a, T: ?Sized + 'a> WriteLock<'a, T> {
    /// Makes a new `WriteLock` to access a sub-part of the current `WriteLock`.
    #[inline]
    pub fn map<U: ?Sized + 'a, F>(self, f: F) -> WriteLock<'a, U>
        where F: FnOnce(&mut T) -> &mut U
    {
        WriteLock {
            inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
            lock: self.lock,
        }
    }
}

impl<'a, T: ?Sized + 'a> Deref for WriteLock<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.inner.deref()
    }
}

impl<'a, T: ?Sized + 'a> DerefMut for WriteLock<'a, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        self.inner.deref_mut()
    }
}

#[cfg(test)]
mod tests {
    use buffer::{BufferUsage, CpuAccessibleBuffer};

    #[test]
    fn create_empty_buffer() {
        let (device, queue) = gfx_dev_and_queue!();

        const EMPTY: [i32; 0] = [];

        let _ = CpuAccessibleBuffer::from_data(device,
                                               BufferUsage::all(),
                                               Some(queue.family()),
                                               EMPTY.iter());
    }
}
<commit_msg>Rework the template parameter of CpuAccessibleBuffer and remove device()<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.

//! Buffer whose content is accessible to the CPU.
//!
//! The `CpuAccessibleBuffer` is a basic general-purpose buffer. It can be used in any situation
//! but may not perform as well as other buffer types.
//!
//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
//! You can read the buffer multiple times simultaneously. Trying to read and write simultaneously,
//! or write and write simultaneously will block.

use smallvec::SmallVec;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr;
use std::sync::Arc;
use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use std::sync::RwLockWriteGuard;
use std::sync::TryLockError;

use buffer::BufferUsage;
use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::TypedBufferAccess;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use instance::QueueFamily;
use memory::Content;
use memory::CpuAccess as MemCpuAccess;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use memory::pool::StdMemoryPoolAlloc;
use sync::AccessError;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::Sharing;

use OomError;

/// Buffer whose content is accessible by the CPU.
#[derive(Debug)]
pub struct CpuAccessibleBuffer<T: ?Sized, A = StdMemoryPoolAlloc> {
    // Inner content.
    inner: UnsafeBuffer,

    // The memory held by the buffer.
    memory: A,

    // Access pattern of the buffer. Can be read-locked for a shared CPU access, or write-locked
    // for either a write CPU access or a GPU access.
    access: RwLock<()>,

    // Queue families allowed to access this buffer.
    queue_families: SmallVec<[u32; 4]>,

    // Necessary to make it compile.
    marker: PhantomData<Box<T>>,
}

impl<T> CpuAccessibleBuffer<T> {
    /// Deprecated. Use `from_data` instead.
    #[deprecated]
    #[inline]
    pub fn new<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
                      -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe { CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families) }
    }

    /// Builds a new buffer with some data in it. Only allowed for sized data.
    pub fn from_data<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I, data: T)
                            -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>,
              T: Content + 'static
    {
        unsafe {
            let uninitialized =
                CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)?;

            // Note that we are in panic-unsafety land here. However a panic should never ever
            // happen here, so in theory we are safe.
            // TODO: check whether that's true ^

            {
                let mut mapping = uninitialized.write().unwrap();
                ptr::write::<T>(&mut *mapping, data)
            }

            Ok(uninitialized)
        }
    }

    /// Builds a new uninitialized buffer. Only allowed for sized data.
    #[inline]
    pub unsafe fn uninitialized<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
                                       -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
    }
}

impl<T> CpuAccessibleBuffer<[T]> {
    /// Builds a new buffer that contains an array `T`. The initial data comes from an iterator
    /// that produces that list of Ts.
    pub fn from_iter<'a, I, Q>(device: Arc<Device>, usage: BufferUsage, queue_families: Q, data: I)
                               -> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
        where I: ExactSizeIterator<Item = T>,
              T: Content + 'static,
              Q: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            let uninitialized = CpuAccessibleBuffer::uninitialized_array(device,
                                                                         data.len(),
                                                                         usage,
                                                                         queue_families)?;

            // Note that we are in panic-unsafety land here. However a panic should never ever
            // happen here, so in theory we are safe.
            // TODO: check whether that's true ^

            {
                let mut mapping = uninitialized.write().unwrap();

                for (i, o) in data.zip(mapping.iter_mut()) {
                    ptr::write(o, i);
                }
            }

            Ok(uninitialized)
        }
    }

    /// Deprecated. Use `uninitialized_array` or `from_iter` instead.
    // TODO: remove
    #[inline]
    #[deprecated]
    pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage, queue_families: I)
                        -> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe { CpuAccessibleBuffer::uninitialized_array(device, len, usage, queue_families) }
    }

    /// Builds a new buffer. Can be used for arrays.
    #[inline]
    pub unsafe fn uninitialized_array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage,
                                             queue_families: I)
                                             -> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        CpuAccessibleBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
    }
}

impl<T: ?Sized> CpuAccessibleBuffer<T> {
    /// Builds a new buffer without checking the size.
    ///
    /// # Safety
    ///
    /// You must ensure that the size that you pass is correct for `T`.
    ///
    pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage,
                             queue_families: I) -> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        let queue_families = queue_families
            .into_iter()
            .map(|f| f.id())
            .collect::<SmallVec<[u32; 4]>>();

        let (buffer, mem_reqs) = {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            match UnsafeBuffer::new(device.clone(), size, usage, sharing, SparseLevel::none()) {
                Ok(b) => b,
                Err(BufferCreationError::OomError(err)) => return Err(err),
                Err(_) => unreachable!(),        // We don't use sparse binding, therefore the other
                // errors can't happen
            }
        };

        let mem_ty = device
            .physical_device()
            .memory_types()
            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
            .filter(|t| t.is_host_visible())
            .next()
            .unwrap(); // Vk specs guarantee that this can't fail

        let mem = MemoryPool::alloc(&Device::standard_pool(&device),
                                    mem_ty,
                                    mem_reqs.size,
                                    mem_reqs.alignment,
                                    AllocLayout::Linear)?;
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        debug_assert!(mem.mapped_memory().is_some());
        buffer.bind_memory(mem.memory(), mem.offset())?;

        Ok(Arc::new(CpuAccessibleBuffer {
                        inner: buffer,
                        memory: mem,
                        access: RwLock::new(()),
                        queue_families: queue_families,
                        marker: PhantomData,
                    }))
    }
}

impl<T: ?Sized, A> CpuAccessibleBuffer<T, A> {
    /// Returns the queue families this buffer can be used on.
    // TODO: use a custom iterator
    #[inline]
    pub fn queue_families(&self) -> Vec<QueueFamily> {
        self.queue_families
            .iter()
            .map(|&num| {
                     self.device()
                         .physical_device()
                         .queue_family_by_id(num)
                         .unwrap()
                 })
            .collect()
    }
}

impl<T: ?Sized, A> CpuAccessibleBuffer<T, A>
    where T: Content + 'static,
          A: MemoryPoolAlloc,
{
    /// Locks the buffer in order to write its content.
    ///
    /// If the buffer is currently in use by the GPU, this function will block until either the
    /// buffer is available or the timeout is reached. A value of `0` for the timeout is valid and
    /// means that the function should never block.
    ///
    /// After this function successfully locks the buffer, any attempt to submit a command buffer
    /// that uses it will block until you unlock it.
    #[inline]
    pub fn read(&self) -> Result<ReadLock<T>, TryLockError<RwLockReadGuard<()>>> {
        let lock = self.access.try_read()?;

        let offset = self.memory.offset();
        let range = offset .. offset + self.inner.size();

        Ok(ReadLock {
               inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
               lock: lock,
           })
    }

    /// Locks the buffer in order to write its content.
    ///
    /// If the buffer is currently in use by the GPU, this function will block until either the
    /// buffer is available or the timeout is reached. A value of `0` for the timeout is valid and
    /// means that the function should never block.
    ///
    /// After this function successfully locks the buffer, any attempt to submit a command buffer
    /// that uses it will block until you unlock it.
    #[inline]
    pub fn write(&self) -> Result<WriteLock<T>, TryLockError<RwLockWriteGuard<()>>> {
        let lock = self.access.try_write()?;

        let offset = self.memory.offset();
        let range = offset .. offset + self.inner.size();

        Ok(WriteLock {
               inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
               lock: lock,
           })
    }
}

unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
    where T: 'static + Send + Sync
{
    #[inline]
    fn inner(&self) -> BufferInner {
        BufferInner {
            buffer: &self.inner,
            offset: 0,
        }
    }

    #[inline]
    fn size(&self) -> usize {
        self.inner.size()
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        self.inner.key()
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
        Ok(()) // FIXME:
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        // FIXME:
    }

    #[inline]
    unsafe fn unlock(&self) {
        // TODO:
    }
}

unsafe impl<T: ?Sized, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
    where T: 'static + Send + Sync
{
    type Content = T;
}

unsafe impl<T: ?Sized, A> DeviceOwned for CpuAccessibleBuffer<T, A> {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }
}

pub struct CpuAccessibleBufferClState {
    size: usize,
    stages: PipelineStages,
    access: AccessFlagBits,
    first_stages: Option<PipelineStages>,
    write: bool,
    earliest_previous_transition: usize,
    needs_flush_at_the_end: bool,
}

pub struct CpuAccessibleBufferFinished {
    first_stages: PipelineStages,
    write: bool,
}

/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
///
/// Note that this object holds a rwlock read guard on the chunk. If another thread tries to access
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
pub struct ReadLock<'a, T: ?Sized + 'a> {
    inner: MemCpuAccess<'a, T>,
    lock: RwLockReadGuard<'a, ()>,
}

impl<'a, T: ?Sized + 'a> ReadLock<'a, T> {
    /// Makes a new `ReadLock` to access a sub-part of the current `ReadLock`.
    #[inline]
    pub fn map<U: ?Sized + 'a, F>(self, f: F) -> ReadLock<'a, U>
        where F: FnOnce(&mut T) -> &mut U
    {
        ReadLock {
            inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
            lock: self.lock,
        }
    }
}

impl<'a, T: ?Sized + 'a> Deref for ReadLock<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.inner.deref()
    }
}

/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
///
/// Note that this object holds a rwlock write guard on the chunk. If another thread tries to access
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
pub struct WriteLock<'a, T: ?Sized + 'a> {
    inner: MemCpuAccess<'a, T>,
    lock: RwLockWriteGuard<'a, ()>,
}

impl<'a, T: ?Sized + 'a> WriteLock<'a, T> {
    /// Makes a new `WriteLock` to access a sub-part of the current `WriteLock`.
    #[inline]
    pub fn map<U: ?Sized + 'a, F>(self, f: F) -> WriteLock<'a, U>
        where F: FnOnce(&mut T) -> &mut U
    {
        WriteLock {
            inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
            lock: self.lock,
        }
    }
}

impl<'a, T: ?Sized + 'a> Deref for WriteLock<'a, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.inner.deref()
    }
}

impl<'a, T: ?Sized + 'a> DerefMut for WriteLock<'a, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        self.inner.deref_mut()
    }
}

#[cfg(test)]
mod tests {
    use buffer::{BufferUsage, CpuAccessibleBuffer};

    #[test]
    fn create_empty_buffer() {
        let (device, queue) = gfx_dev_and_queue!();

        const EMPTY: [i32; 0] = [];

        let _ = CpuAccessibleBuffer::from_data(device,
                                               BufferUsage::all(),
                                               Some(queue.family()),
                                               EMPTY.iter());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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.

//! Viewports and scissor boxes.
//!
//! There are two different concepts to determine where things will be drawn:
//!
//! - The viewport is the region of the image which corresponds to the
//!   vertex coordinates `-1.0` to `1.0`.
//! - Any pixel outside of the scissor box will be discarded.
//!
//! In other words modifying the viewport will stretch the image, while modifying the scissor
//! box acts like a filter.
//!
//! It is legal and sensible to use a viewport that is larger than the target image or that
//! only partially overlaps the target image.
//!
//! # Multiple viewports
//!
//! In most situations, you only need a single viewport and a single scissor box.
//!
//! If, however, you use a geometry shader, you can specify multiple viewports and scissor boxes.
//! Then in your geometry shader you can specify in which viewport and scissor box the primitive
//! should be written to. In GLSL this is done by writing to the special variable
//! `gl_ViewportIndex`.
//!
//! If you don't use a geometry shader or use a geometry shader where don't set which viewport to
//! use, then the first viewport and scissor box will be used.
//!
//! # Dynamic and fixed
//!
//! Vulkan allows four different setups:
//!
//! - The state of both the viewports and scissor boxes is known at pipeline creation.
//! - The state of viewports is known at pipeline creation, but the state of scissor boxes is
//!   only known when submitting the draw command.
//! - The state of scissor boxes is known at pipeline creation, but the state of viewports is
//!   only known when submitting the draw command.
//! - The state of both the viewports and scissor boxes is only known when submitting the
//!   draw command.
//!
//! In all cases the number of viewports and scissor boxes must be the same.
//!

use std::ops::Range;
use crate::vk;

/// List of viewports and scissors that are used when creating a graphics pipeline object.
///
/// Note that the number of viewports and scissors must be the same.
#[derive(Debug, Clone)]
pub enum ViewportsState {
    /// The state is known in advance.
    Fixed {
        /// State of the viewports and scissors.
        data: Vec<(Viewport, Scissor)>,
    },

    /// The state of scissors is known in advance, but the state of viewports is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicViewports {
        /// State of the scissors.
        scissors: Vec<Scissor>,
    },

    /// The state of viewports is known in advance, but the state of scissors is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicScissors {
        /// State of the viewports
        viewports: Vec<Viewport>,
    },

    /// The state of both the viewports and scissors is dynamic and will be set when drawing.
    Dynamic {
        /// Number of viewports and scissors.
        num: u32,
    },
}

impl ViewportsState {
    /// Returns true if the state of the viewports is dynamic.
    pub fn dynamic_viewports(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => true,
            ViewportsState::DynamicScissors { .. } => false,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns true if the state of the scissors is dynamic.
    pub fn dynamic_scissors(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => false,
            ViewportsState::DynamicScissors { .. } => true,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns the number of viewports and scissors.
    pub fn num_viewports(&self) -> u32 {
        match *self {
            ViewportsState::Fixed { ref data } => data.len() as u32,
            ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
            ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
            ViewportsState::Dynamic { num } => num,
        }
    }
}

/// State of a single viewport.
// FIXME: check that:
//        x + width must be less than or equal to viewportBoundsRange[0]
//        y + height must be less than or equal to viewportBoundsRange[1]
#[derive(Debug, Clone, PartialEq)]
pub struct Viewport {
    /// Coordinates in pixels of the top-left hand corner of the viewport.
    pub origin: [f32; 2],

    /// Dimensions in pixels of the viewport.
    pub dimensions: [f32; 2],

    /// Minimum and maximum values of the depth.
    ///
    /// The values `0.0` to `1.0` of each vertex's Z coordinate will be mapped to this
    /// `depth_range` before being compared to the existing depth value.
    ///
    /// This is equivalents to `glDepthRange` in OpenGL, except that OpenGL uses the Z coordinate
    /// range from `-1.0` to `1.0` instead.
    pub depth_range: Range<f32>,
}

impl Viewport {
    #[inline]
    pub(crate) fn into_vulkan_viewport(self) -> vk::Viewport {
        vk::Viewport {
            x: self.origin[0],
            y: self.origin[1],
            width: self.dimensions[0],
            height: self.dimensions[1],
            minDepth: self.depth_range.start,
            maxDepth: self.depth_range.end,
        }
    }
}

/// State of a single scissor box.
// FIXME: add a check:
//      Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow
//      Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Scissor {
    /// Coordinates in pixels of the top-left hand corner of the box.
    pub origin: [i32; 2],

    /// Dimensions in pixels of the box.
    pub dimensions: [u32; 2],
}

impl Scissor {
    /// Defines a scissor box that it outside of the image.
    #[inline]
    pub fn irrelevant() -> Scissor {
        Scissor {
            origin: [0, 0],
            dimensions: [0x7fffffff, 0x7fffffff],
        }
    }

    #[inline]
    pub(crate) fn into_vulkan_rect(self) -> vk::Rect2D {
        vk::Rect2D {
            offset: vk::Offset2D {
                x: self.origin[0],
                y: self.origin[1],
            },
            extent: vk::Extent2D {
                width: self.dimensions[0],
                height: self.dimensions[1],
            },
        }
    }
}

impl Default for Scissor {
    #[inline]
    fn default() -> Scissor {
        Scissor::irrelevant()
    }
}
<commit_msg>fix typo in scissor doc comment (#1528)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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.

//! Viewports and scissor boxes.
//!
//! There are two different concepts to determine where things will be drawn:
//!
//! - The viewport is the region of the image which corresponds to the
//!   vertex coordinates `-1.0` to `1.0`.
//! - Any pixel outside of the scissor box will be discarded.
//!
//! In other words modifying the viewport will stretch the image, while modifying the scissor
//! box acts like a filter.
//!
//! It is legal and sensible to use a viewport that is larger than the target image or that
//! only partially overlaps the target image.
//!
//! # Multiple viewports
//!
//! In most situations, you only need a single viewport and a single scissor box.
//!
//! If, however, you use a geometry shader, you can specify multiple viewports and scissor boxes.
//! Then in your geometry shader you can specify in which viewport and scissor box the primitive
//! should be written to. In GLSL this is done by writing to the special variable
//! `gl_ViewportIndex`.
//!
//! If you don't use a geometry shader or use a geometry shader where don't set which viewport to
//! use, then the first viewport and scissor box will be used.
//!
//! # Dynamic and fixed
//!
//! Vulkan allows four different setups:
//!
//! - The state of both the viewports and scissor boxes is known at pipeline creation.
//! - The state of viewports is known at pipeline creation, but the state of scissor boxes is
//!   only known when submitting the draw command.
//! - The state of scissor boxes is known at pipeline creation, but the state of viewports is
//!   only known when submitting the draw command.
//! - The state of both the viewports and scissor boxes is only known when submitting the
//!   draw command.
//!
//! In all cases the number of viewports and scissor boxes must be the same.
//!

use crate::vk;
use std::ops::Range;

/// List of viewports and scissors that are used when creating a graphics pipeline object.
///
/// Note that the number of viewports and scissors must be the same.
#[derive(Debug, Clone)]
pub enum ViewportsState {
    /// The state is known in advance.
    Fixed {
        /// State of the viewports and scissors.
        data: Vec<(Viewport, Scissor)>,
    },

    /// The state of scissors is known in advance, but the state of viewports is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicViewports {
        /// State of the scissors.
        scissors: Vec<Scissor>,
    },

    /// The state of viewports is known in advance, but the state of scissors is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicScissors {
        /// State of the viewports
        viewports: Vec<Viewport>,
    },

    /// The state of both the viewports and scissors is dynamic and will be set when drawing.
    Dynamic {
        /// Number of viewports and scissors.
        num: u32,
    },
}

impl ViewportsState {
    /// Returns true if the state of the viewports is dynamic.
    pub fn dynamic_viewports(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => true,
            ViewportsState::DynamicScissors { .. } => false,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns true if the state of the scissors is dynamic.
    pub fn dynamic_scissors(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => false,
            ViewportsState::DynamicScissors { .. } => true,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns the number of viewports and scissors.
    pub fn num_viewports(&self) -> u32 {
        match *self {
            ViewportsState::Fixed { ref data } => data.len() as u32,
            ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
            ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
            ViewportsState::Dynamic { num } => num,
        }
    }
}

/// State of a single viewport.
// FIXME: check that:
//        x + width must be less than or equal to viewportBoundsRange[0]
//        y + height must be less than or equal to viewportBoundsRange[1]
#[derive(Debug, Clone, PartialEq)]
pub struct Viewport {
    /// Coordinates in pixels of the top-left hand corner of the viewport.
    pub origin: [f32; 2],

    /// Dimensions in pixels of the viewport.
    pub dimensions: [f32; 2],

    /// Minimum and maximum values of the depth.
    ///
    /// The values `0.0` to `1.0` of each vertex's Z coordinate will be mapped to this
    /// `depth_range` before being compared to the existing depth value.
    ///
    /// This is equivalents to `glDepthRange` in OpenGL, except that OpenGL uses the Z coordinate
    /// range from `-1.0` to `1.0` instead.
    pub depth_range: Range<f32>,
}

impl Viewport {
    #[inline]
    pub(crate) fn into_vulkan_viewport(self) -> vk::Viewport {
        vk::Viewport {
            x: self.origin[0],
            y: self.origin[1],
            width: self.dimensions[0],
            height: self.dimensions[1],
            minDepth: self.depth_range.start,
            maxDepth: self.depth_range.end,
        }
    }
}

/// State of a single scissor box.
// FIXME: add a check:
//      Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow
//      Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Scissor {
    /// Coordinates in pixels of the top-left hand corner of the box.
    pub origin: [i32; 2],

    /// Dimensions in pixels of the box.
    pub dimensions: [u32; 2],
}

impl Scissor {
    /// Returns a scissor that, when used, will instruct the pipeline to draw to the entire framebuffer.
    #[inline]
    pub fn irrelevant() -> Scissor {
        Scissor {
            origin: [0, 0],
            dimensions: [0x7fffffff, 0x7fffffff],
        }
    }

    #[inline]
    pub(crate) fn into_vulkan_rect(self) -> vk::Rect2D {
        vk::Rect2D {
            offset: vk::Offset2D {
                x: self.origin[0],
                y: self.origin[1],
            },
            extent: vk::Extent2D {
                width: self.dimensions[0],
                height: self.dimensions[1],
            },
        }
    }
}

impl Default for Scissor {
    #[inline]
    fn default() -> Scissor {
        Scissor::irrelevant()
    }
}
<|endoftext|>


<commit_before>
extern crate norx;
use std::str::from_utf8;
use norx::norx6441::{encrypt,decrypt};

pub fn main() {
    let k = [0u8, ..32];
    let n = [0u8, ..16];
    let m = "Hello, World!";
    let c = encrypt(&[], m.as_bytes(), &[], &n, &k);
    for x in c.iter() {
        print!("{:02x} ", *x);
    }
    println!("");
    match decrypt(&[], c.as_slice(), &[], &n, &k) {
        Some(m) => println!("{}", from_utf8(m.as_slice()).expect("bad utf-8")),
          None  => println!("bad ciphertext")
    }
    let mut c = c;
    c[0] ^= 1; // flip a bit
    match decrypt(&[], c.as_slice(), &[], &n, &k) {
        Some(m) => println!("{}", from_utf8(m.as_slice()).expect("bad utf-8")),
          None  => println!("bad ciphertext")
    }
}

<commit_msg>Fix example<commit_after>
extern crate norx;
use std::str::from_utf8;
use norx::norx6441::{encrypt,decrypt};

pub fn main() {
    let k = [0u8; 32];
    let n = [0u8; 16];
    let m = "Hello, World!";
    let c = encrypt(&[], m.as_bytes(), &[], &n, &k);
    for x in c.iter() {
        print!("{:02x} ", *x);
    }
    println!("");
    match decrypt(&[], c.as_slice(), &[], &n, &k) {
        Some(m) => println!("{}", from_utf8(m.as_slice()).unwrap()),
          None  => println!("bad ciphertext")
    }
    let mut c = c;
    c[0] ^= 1; // flip a bit
    match decrypt(&[], c.as_slice(), &[], &n, &k) {
        Some(m) => println!("{}", from_utf8(m.as_slice()).unwrap()),
          None  => println!("bad ciphertext")
    }
}

<|endoftext|>


<commit_before>// Extracting metadata from crate files

import driver::session;
import syntax::ast;
import lib::llvm::False;
import lib::llvm::llvm;
import lib::llvm::mk_object_file;
import lib::llvm::mk_section_iter;
import front::attr;
import middle::resolve;
import syntax::walk;
import syntax::codemap::span;
import back::x86;
import util::common;
import std::ivec;
import std::str;
import std::vec;
import std::ebml;
import std::fs;
import std::io;
import std::option;
import std::option::none;
import std::option::some;
import std::map::hashmap;
import std::map::new_int_hash;
import syntax::print::pprust;
import common::*;

export read_crates;
export list_file_metadata;

// Traverses an AST, reading all the information about use'd crates and native
// libraries necessary for later resolving, typechecking, linking, etc.
fn read_crates(session::session sess,
               &ast::crate crate) {
    auto e =
        @rec(sess=sess,
             crate_cache=@std::map::new_str_hash[int](),
             library_search_paths=sess.get_opts().library_search_paths,
             mutable next_crate_num=1);
    auto v =
        rec(visit_view_item_pre=bind visit_view_item(e, _),
            visit_item_pre=bind visit_item(e, _)
            with walk::default_visitor());
    walk::walk_crate(v, crate);
}

type env =
    @rec(session::session sess,
         @hashmap[str, int] crate_cache,
         vec[str] library_search_paths,
         mutable ast::crate_num next_crate_num);

fn visit_view_item(env e, &@ast::view_item i) {
    alt (i.node) {
        case (ast::view_item_use(?ident, ?meta_items, ?id)) {
            auto cnum = resolve_crate(e, ident, meta_items, i.span);
            cstore::add_use_stmt_cnum(e.sess.get_cstore(), id, cnum);
        }
        case (_) { }
    }
}

fn visit_item(env e, &@ast::item i) {
    alt (i.node) {
        case (ast::item_native_mod(?m)) {
            if (m.abi != ast::native_abi_rust &&
                m.abi != ast::native_abi_cdecl) {
                ret;
            }
            auto cstore = e.sess.get_cstore();
            if (!cstore::add_used_library(cstore, m.native_name)) {
                ret;
            }
            for (ast::attribute a in
                     attr::find_attrs_by_name(i.attrs, "link_args")) {
                alt (attr::get_meta_item_value_str(attr::attr_meta(a))) {
                    case (some(?linkarg)) {
                        cstore::add_used_link_args(cstore, linkarg);
                    }
                    case (none) { /* fallthrough */ }
                }
            }
        }
        case (_) {
        }
    }
}

// A diagnostic function for dumping crate metadata to an output stream
fn list_file_metadata(str path, io::writer out) {
    alt (get_metadata_section(path)) {
        case (option::some(?bytes)) {
            decoder::list_crate_metadata(bytes, out);
        }
        case (option::none) {
            out.write_str("Could not find metadata in " + path + ".\n");
        }
    }
}

fn metadata_matches(&vec[u8] crate_data,
                    &(@ast::meta_item)[] metas) -> bool {
    auto attrs = decoder::get_crate_attributes(crate_data);
    auto linkage_metas = attr::find_linkage_metas(attrs);

    log #fmt("matching %u metadata requirements against %u items",
             ivec::len(metas), ivec::len(linkage_metas));

    for (@ast::meta_item needed in metas) {
        if (!attr::contains(linkage_metas, needed)) {
            log #fmt("missing %s", pprust::meta_item_to_str(*needed));
            ret false;
        }
    }
    ret true;
}

fn default_native_lib_naming(session::session sess, bool static) ->
   rec(str prefix, str suffix) {
    if (static) {
        ret rec(prefix="lib", suffix=".rlib");
    }
    alt (sess.get_targ_cfg().os) {
        case (session::os_win32) { ret rec(prefix="", suffix=".dll"); }
        case (session::os_macos) { ret rec(prefix="lib", suffix=".dylib"); }
        case (session::os_linux) { ret rec(prefix="lib", suffix=".so"); }
    }
}

fn find_library_crate(&session::session sess, &ast::ident ident,
                      &(@ast::meta_item)[] metas,
                      &vec[str] library_search_paths) ->
   option::t[tup(str, vec[u8])] {

    attr::require_unique_names(sess, metas);

    auto crate_name = {
        auto name_items = attr::find_meta_items_by_name(metas, "name");
        alt (ivec::last(name_items)) {
            case (some(?i)) {
                alt (attr::get_meta_item_value_str(i)) {
                    case (some(?n)) { n }
                    case (_) {
                        // FIXME: Probably want a warning here since the user
                        // is using the wrong type of meta item
                        ident
                    }
                }
            }
            case (none) { ident }
        }
    };

    auto nn = default_native_lib_naming(sess, sess.get_opts().static);
    auto x = find_library_crate_aux(nn, crate_name, metas,
                                    library_search_paths);
    if (x != none || sess.get_opts().static) {
        ret x;
    }
    auto nn2 = default_native_lib_naming(sess, true);
    ret find_library_crate_aux(nn2, crate_name, metas, library_search_paths);
}

fn find_library_crate_aux(&rec(str prefix, str suffix) nn, str crate_name,
                          &(@ast::meta_item)[] metas,
                          &vec[str] library_search_paths) ->
                          option::t[tup(str, vec[u8])] {
    let str prefix = nn.prefix + crate_name;
    // FIXME: we could probably use a 'glob' function in std::fs but it will
    // be much easier to write once the unsafe module knows more about FFI
    // tricks. Currently the glob(3) interface is a bit more than we can
    // stomach from here, and writing a C++ wrapper is more work than just
    // manually filtering fs::list_dir here.

    for (str library_search_path in library_search_paths) {
        log #fmt("searching %s", library_search_path);
        for (str path in fs::list_dir(library_search_path)) {
            log #fmt("searching %s", path);
            let str f = fs::basename(path);
            if (!(str::starts_with(f, prefix) &&
                      str::ends_with(f, nn.suffix))) {
                log #fmt("skipping %s, doesn't look like %s*%s", path, prefix,
                         nn.suffix);
                cont;
            }
            alt (get_metadata_section(path)) {
                case (option::some(?cvec)) {
                    if (!metadata_matches(cvec, metas)) {
                        log #fmt("skipping %s, metadata doesn't match", path);
                        cont;
                    }
                    log #fmt("found %s with matching metadata", path);
                    ret some(tup(path, cvec));
                }
                case (_) { }
            }
        }
    }
    ret none;
}

fn get_metadata_section(str filename) -> option::t[vec[u8]] {
    auto b = str::buf(filename);
    auto mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(b);
    if (mb as int == 0) { ret option::none[vec[u8]]; }
    auto of = mk_object_file(mb);
    auto si = mk_section_iter(of.llof);
    while (llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False) {
        auto name_buf = llvm::LLVMGetSectionName(si.llsi);
        auto name = str::str_from_cstr(name_buf);
        if (str::eq(name, x86::get_meta_sect_name())) {
            auto cbuf = llvm::LLVMGetSectionContents(si.llsi);
            auto csz = llvm::LLVMGetSectionSize(si.llsi);
            auto cvbuf = cbuf as vec::vbuf;
            ret option::some[vec[u8]](vec::vec_from_vbuf[u8](cvbuf, csz));
        }
        llvm::LLVMMoveToNextSection(si.llsi);
    }
    ret option::none[vec[u8]];
}

fn load_library_crate(&session::session sess, span span, ast::crate_num cnum,
                      &ast::ident ident, &(@ast::meta_item)[] metas,
                      &vec[str] library_search_paths) {
    alt (find_library_crate(sess, ident, metas, library_search_paths)) {
        case (some(?t)) {
            auto cstore = sess.get_cstore();
            auto cmeta = rec(name=ident,
                             data=t._1,
                             cnum_map = new_int_hash[ast::crate_num]());
            cstore::set_crate_data(cstore, cnum, cmeta);
            cstore::add_used_crate_file(cstore, t._0);
            ret;
        }
        case (_) { }
    }
    sess.span_fatal(span, #fmt("can't find crate for '%s'", ident));
}

fn resolve_crate(env e, ast::ident ident, (@ast::meta_item)[] metas,
                 span span) -> ast::crate_num {
    if (!e.crate_cache.contains_key(ident)) {
        auto cnum = e.next_crate_num;
        load_library_crate(e.sess, span, cnum, ident,
                           metas, e.library_search_paths);
        e.crate_cache.insert(ident, e.next_crate_num);
        e.next_crate_num += 1;
        ret cnum;
    } else {
        ret e.crate_cache.get(ident);
    }
 }

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Refactor load_library_crate and resolve_crate<commit_after>// Extracting metadata from crate files

import driver::session;
import syntax::ast;
import lib::llvm::False;
import lib::llvm::llvm;
import lib::llvm::mk_object_file;
import lib::llvm::mk_section_iter;
import front::attr;
import middle::resolve;
import syntax::walk;
import syntax::codemap::span;
import back::x86;
import util::common;
import std::ivec;
import std::str;
import std::vec;
import std::ebml;
import std::fs;
import std::io;
import std::option;
import std::option::none;
import std::option::some;
import std::map::hashmap;
import std::map::new_int_hash;
import syntax::print::pprust;
import common::*;

export read_crates;
export list_file_metadata;

// Traverses an AST, reading all the information about use'd crates and native
// libraries necessary for later resolving, typechecking, linking, etc.
fn read_crates(session::session sess,
               &ast::crate crate) {
    auto e =
        @rec(sess=sess,
             crate_cache=@std::map::new_str_hash[int](),
             library_search_paths=sess.get_opts().library_search_paths,
             mutable next_crate_num=1);
    auto v =
        rec(visit_view_item_pre=bind visit_view_item(e, _),
            visit_item_pre=bind visit_item(e, _)
            with walk::default_visitor());
    walk::walk_crate(v, crate);
}

type env =
    @rec(session::session sess,
         @hashmap[str, int] crate_cache,
         vec[str] library_search_paths,
         mutable ast::crate_num next_crate_num);

fn visit_view_item(env e, &@ast::view_item i) {
    alt (i.node) {
        case (ast::view_item_use(?ident, ?meta_items, ?id)) {
            auto cnum = resolve_crate(e, ident, meta_items, i.span);
            cstore::add_use_stmt_cnum(e.sess.get_cstore(), id, cnum);
        }
        case (_) { }
    }
}

fn visit_item(env e, &@ast::item i) {
    alt (i.node) {
        case (ast::item_native_mod(?m)) {
            if (m.abi != ast::native_abi_rust &&
                m.abi != ast::native_abi_cdecl) {
                ret;
            }
            auto cstore = e.sess.get_cstore();
            if (!cstore::add_used_library(cstore, m.native_name)) {
                ret;
            }
            for (ast::attribute a in
                     attr::find_attrs_by_name(i.attrs, "link_args")) {
                alt (attr::get_meta_item_value_str(attr::attr_meta(a))) {
                    case (some(?linkarg)) {
                        cstore::add_used_link_args(cstore, linkarg);
                    }
                    case (none) { /* fallthrough */ }
                }
            }
        }
        case (_) {
        }
    }
}

// A diagnostic function for dumping crate metadata to an output stream
fn list_file_metadata(str path, io::writer out) {
    alt (get_metadata_section(path)) {
        case (option::some(?bytes)) {
            decoder::list_crate_metadata(bytes, out);
        }
        case (option::none) {
            out.write_str("Could not find metadata in " + path + ".\n");
        }
    }
}

fn metadata_matches(&vec[u8] crate_data,
                    &(@ast::meta_item)[] metas) -> bool {
    auto attrs = decoder::get_crate_attributes(crate_data);
    auto linkage_metas = attr::find_linkage_metas(attrs);

    log #fmt("matching %u metadata requirements against %u items",
             ivec::len(metas), ivec::len(linkage_metas));

    for (@ast::meta_item needed in metas) {
        if (!attr::contains(linkage_metas, needed)) {
            log #fmt("missing %s", pprust::meta_item_to_str(*needed));
            ret false;
        }
    }
    ret true;
}

fn default_native_lib_naming(session::session sess, bool static) ->
   rec(str prefix, str suffix) {
    if (static) {
        ret rec(prefix="lib", suffix=".rlib");
    }
    alt (sess.get_targ_cfg().os) {
        case (session::os_win32) { ret rec(prefix="", suffix=".dll"); }
        case (session::os_macos) { ret rec(prefix="lib", suffix=".dylib"); }
        case (session::os_linux) { ret rec(prefix="lib", suffix=".so"); }
    }
}

fn find_library_crate(&session::session sess, &ast::ident ident,
                      &(@ast::meta_item)[] metas,
                      &vec[str] library_search_paths) ->
   option::t[tup(str, vec[u8])] {

    attr::require_unique_names(sess, metas);

    auto crate_name = {
        auto name_items = attr::find_meta_items_by_name(metas, "name");
        alt (ivec::last(name_items)) {
            case (some(?i)) {
                alt (attr::get_meta_item_value_str(i)) {
                    case (some(?n)) { n }
                    case (_) {
                        // FIXME: Probably want a warning here since the user
                        // is using the wrong type of meta item
                        ident
                    }
                }
            }
            case (none) { ident }
        }
    };

    auto nn = default_native_lib_naming(sess, sess.get_opts().static);
    auto x = find_library_crate_aux(nn, crate_name, metas,
                                    library_search_paths);
    if (x != none || sess.get_opts().static) {
        ret x;
    }
    auto nn2 = default_native_lib_naming(sess, true);
    ret find_library_crate_aux(nn2, crate_name, metas, library_search_paths);
}

fn find_library_crate_aux(&rec(str prefix, str suffix) nn, str crate_name,
                          &(@ast::meta_item)[] metas,
                          &vec[str] library_search_paths) ->
                          option::t[tup(str, vec[u8])] {
    let str prefix = nn.prefix + crate_name;
    // FIXME: we could probably use a 'glob' function in std::fs but it will
    // be much easier to write once the unsafe module knows more about FFI
    // tricks. Currently the glob(3) interface is a bit more than we can
    // stomach from here, and writing a C++ wrapper is more work than just
    // manually filtering fs::list_dir here.

    for (str library_search_path in library_search_paths) {
        log #fmt("searching %s", library_search_path);
        for (str path in fs::list_dir(library_search_path)) {
            log #fmt("searching %s", path);
            let str f = fs::basename(path);
            if (!(str::starts_with(f, prefix) &&
                      str::ends_with(f, nn.suffix))) {
                log #fmt("skipping %s, doesn't look like %s*%s", path, prefix,
                         nn.suffix);
                cont;
            }
            alt (get_metadata_section(path)) {
                case (option::some(?cvec)) {
                    if (!metadata_matches(cvec, metas)) {
                        log #fmt("skipping %s, metadata doesn't match", path);
                        cont;
                    }
                    log #fmt("found %s with matching metadata", path);
                    ret some(tup(path, cvec));
                }
                case (_) { }
            }
        }
    }
    ret none;
}

fn get_metadata_section(str filename) -> option::t[vec[u8]] {
    auto b = str::buf(filename);
    auto mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(b);
    if (mb as int == 0) { ret option::none[vec[u8]]; }
    auto of = mk_object_file(mb);
    auto si = mk_section_iter(of.llof);
    while (llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False) {
        auto name_buf = llvm::LLVMGetSectionName(si.llsi);
        auto name = str::str_from_cstr(name_buf);
        if (str::eq(name, x86::get_meta_sect_name())) {
            auto cbuf = llvm::LLVMGetSectionContents(si.llsi);
            auto csz = llvm::LLVMGetSectionSize(si.llsi);
            auto cvbuf = cbuf as vec::vbuf;
            ret option::some[vec[u8]](vec::vec_from_vbuf[u8](cvbuf, csz));
        }
        llvm::LLVMMoveToNextSection(si.llsi);
    }
    ret option::none[vec[u8]];
}

fn load_library_crate(&session::session sess, span span,
                      &ast::ident ident, &(@ast::meta_item)[] metas,
                      &vec[str] library_search_paths)
    -> tup(str, vec[u8]) {

    alt (find_library_crate(sess, ident, metas, library_search_paths)) {
        case (some(?t)) {
            ret t;
        }
        case (none) {
            sess.span_fatal(span, #fmt("can't find crate for '%s'", ident));
        }
    }
}

fn resolve_crate(env e, ast::ident ident, (@ast::meta_item)[] metas,
                 span span) -> ast::crate_num {
    if (!e.crate_cache.contains_key(ident)) {
        auto cinfo = load_library_crate(e.sess, span, ident, metas,
                                        e.library_search_paths);

        auto cfilename = cinfo._0;
        auto cdata = cinfo._1;

        auto cmeta = rec(name=ident,
                         data=cdata,
                         cnum_map = new_int_hash[ast::crate_num]());

        auto cnum = e.next_crate_num;
        e.crate_cache.insert(ident, cnum);
        e.next_crate_num += 1;

        auto cstore = e.sess.get_cstore();
        cstore::set_crate_data(cstore, cnum, cmeta);
        cstore::add_used_crate_file(cstore, cfilename);
        ret cnum;
    } else {
        ret e.crate_cache.get(ident);
    }
 }

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>//! RAII wrapper for using a KataOS copyregion object.

#![no_std]
#![allow(non_camel_case_types)]

use core::mem::size_of;

use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_Default_VMAttributes;
use sel4_sys::seL4_Page_Map;
use sel4_sys::seL4_Page_Unmap;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_Word;

extern "C" {
    static SELF_VSPACE_ROOT: seL4_CPtr;
}

// Sample usage:
// let mut copy_region = CopyRegion::new(unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])}, PAGE_SIZE);
// copy_region.map(frame.cptr)?;
// copy_region.as_mut()[..].fill(0);
// let start = if index > 0 { 0 } else { vaddr - data_range.start };
// let end = cmp::min(data_range.end - vaddr, copy_region.size());
// image.read_exact(&mut copy_region.as_mut()[start..end])
//      .map_err(|_| seL4_Error::seL4_NoError)?; // XXX
// copy_region.unmap()?;

// TODO(sleffler): do we need to parameterize VM_Attributes & CapRights?
// TODO(sleffler): Mutex-wrapped & maybe RefCell-wrapped versions?

// Fn from the criterion crate that convinces the optimizer
// a value is used in order to defeat premature optimization.
fn black_box<T>(dummy: T) -> T {
    unsafe {
        let ret = core::ptr::read_volatile(&dummy);
        core::mem::forget(dummy);
        ret
    }
}

pub struct CopyRegion {
    region: *mut seL4_Word,
    size: usize,
    cur_frame: Option<seL4_CPtr>,
}
impl CopyRegion {
    pub fn new(region: *mut seL4_Word, size: usize) -> Self {
        CopyRegion {
            region,
            size,
            cur_frame: None,
        }
    }

    // Returns the region size in bytes.
    pub fn size(&self) -> usize {
        self.size
    }

    // Returns the region size if mapped, otherwise 0.
    pub fn mapped_bytes(&self) -> usize {
        if self.cur_frame.is_some() {
            self.size
        } else {
            0
        }
    }

    // Returns an immutable [u8] ref to the mapped region.
    pub fn as_ref(&mut self) -> &[u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region as _, self.size) }
    }

    // Returns a mutable [u8] ref to the mapped region.
    pub fn as_mut(&mut self) -> &mut [u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region as _, self.size) }
    }

    // Returns an immutable [seL4_Word] ref to the mapped region.
    pub fn as_word_ref(&mut self) -> &[seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Returns a mutable [seL4_Word] ref to the mapped region.
    pub fn as_word_mut(&mut self) -> &mut [seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Maps the |frame| in the SELF_VSPACE_ROOT for r/w.
    // XXX need rights + attribs?
    pub fn map(&mut self, frame: seL4_CPtr) -> seL4_Result {
        black_box(frame); // NB: compiler WAR for frame clobber
        unsafe {
            seL4_Page_Map(
                frame,
                SELF_VSPACE_ROOT,
                self.region as seL4_Word,
                // seL4_ReadWrite
                seL4_CapRights::new(
                    /*grant_reply=*/ 0, /*grant=*/ 0, /*read=*/ 1, /*write=*/ 1,
                ),
                seL4_Default_VMAttributes,
            )
        }?;
        self.cur_frame = Some(frame);
        Ok(())
    }

    // Unmaps the current frame, if any.
    pub fn unmap(&mut self) -> seL4_Result {
        if let Some(cptr) = self.cur_frame {
            #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
            unsafe { seL4_ARM_Page_Unify_Instruction(cptr, 0, self.size()) }?;

            unsafe { seL4_Page_Unmap(cptr) }?;
            self.cur_frame = None;
        }
        Ok(())
    }
}
impl Drop for CopyRegion {
    fn drop(&mut self) {
        self.unmap().expect("CopyRegion");
    }
}
<commit_msg>kata-os-model: portability fix<commit_after>//! RAII wrapper for using a KataOS copyregion object.

#![no_std]
#![allow(non_camel_case_types)]

use core::mem::size_of;

use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_Default_VMAttributes;
use sel4_sys::seL4_Page_Map;
use sel4_sys::seL4_Page_Unmap;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_Word;

extern "C" {
    static SELF_VSPACE_ROOT: seL4_CPtr;
}

// Sample usage:
// let mut copy_region = CopyRegion::new(unsafe { ptr::addr_of_mut!(LOAD_APPLICATION[0])}, PAGE_SIZE);
// copy_region.map(frame.cptr)?;
// copy_region.as_mut()[..].fill(0);
// let start = if index > 0 { 0 } else { vaddr - data_range.start };
// let end = cmp::min(data_range.end - vaddr, copy_region.size());
// image.read_exact(&mut copy_region.as_mut()[start..end])
//      .map_err(|_| seL4_Error::seL4_NoError)?; // XXX
// copy_region.unmap()?;

// TODO(sleffler): do we need to parameterize VM_Attributes & CapRights?
// TODO(sleffler): Mutex-wrapped & maybe RefCell-wrapped versions?

// Fn from the criterion crate that convinces the optimizer
// a value is used in order to defeat premature optimization.
fn black_box<T>(dummy: T) -> T {
    unsafe {
        let ret = core::ptr::read_volatile(&dummy);
        core::mem::forget(dummy);
        ret
    }
}

pub struct CopyRegion {
    region: *mut seL4_Word,
    size: usize,
    cur_frame: Option<seL4_CPtr>,
}
impl CopyRegion {
    pub fn new(region: *mut seL4_Word, size: usize) -> Self {
        CopyRegion {
            region,
            size,
            cur_frame: None,
        }
    }

    // Returns the region size in bytes.
    pub fn size(&self) -> usize {
        self.size
    }

    // Returns the region size if mapped, otherwise 0.
    pub fn mapped_bytes(&self) -> usize {
        if self.cur_frame.is_some() {
            self.size
        } else {
            0
        }
    }

    // Returns an immutable [u8] ref to the mapped region.
    pub fn as_ref(&mut self) -> &[u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region as _, self.size) }
    }

    // Returns a mutable [u8] ref to the mapped region.
    pub fn as_mut(&mut self) -> &mut [u8] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region as _, self.size) }
    }

    // Returns an immutable [seL4_Word] ref to the mapped region.
    pub fn as_word_ref(&mut self) -> &[seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Returns a mutable [seL4_Word] ref to the mapped region.
    pub fn as_word_mut(&mut self) -> &mut [seL4_Word] {
        assert!(self.cur_frame.is_some());
        unsafe { core::slice::from_raw_parts_mut(self.region, self.size / size_of::<seL4_Word>()) }
    }

    // Maps the |frame| in the SELF_VSPACE_ROOT for r/w.
    // XXX need rights + attribs?
    pub fn map(&mut self, frame: seL4_CPtr) -> seL4_Result {
        black_box(frame); // NB: compiler WAR for frame clobber
        unsafe {
            seL4_Page_Map(
                frame,
                SELF_VSPACE_ROOT,
                self.region as seL4_Word,
                // seL4_ReadWrite
                seL4_CapRights::new(
                    /*grant_reply=*/ 0, /*grant=*/ 0, /*read=*/ 1, /*write=*/ 1,
                ),
                seL4_Default_VMAttributes,
            )
        }?;
        self.cur_frame = Some(frame);
        Ok(())
    }

    // Unmaps the current frame, if any.
    pub fn unmap(&mut self) -> seL4_Result {
        if let Some(cptr) = self.cur_frame {
            #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
            unsafe { sel4_sys::seL4_ARM_Page_Unify_Instruction(cptr, 0, self.size()) }?;

            unsafe { seL4_Page_Unmap(cptr) }?;
            self.cur_frame = None;
        }
        Ok(())
    }
}
impl Drop for CopyRegion {
    fn drop(&mut self) {
        self.unmap().expect("CopyRegion");
    }
}
<|endoftext|>