<commit_before>/* Copyright 2018 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use super::{
    BinaryReader, BinaryReaderError, OperatorsReader, Result, SectionIteratorLimited,
    SectionReader, SectionWithLimitedItems, Type,
};

#[derive(Debug)]
pub struct FunctionBody<'a> {
    offset: usize,
    data: &'a [u8],
}

impl<'a> FunctionBody<'a> {
    pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
    where
        'a: 'b,
    {
        BinaryReader::new_with_offset(self.data, self.offset)
    }

    fn skip_locals(reader: &mut BinaryReader) -> Result<()> {
        let count = reader.read_var_u32()?;
        for _ in 0..count {
            reader.skip_var_32()?;
            reader.skip_type()?;
        }
        Ok(())
    }

    pub fn get_locals_reader<'b>(&self) -> Result<LocalsReader<'b>>
    where
        'a: 'b,
    {
        let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
        let count = reader.read_var_u32()?;
        Ok(LocalsReader { reader, count })
    }

    pub fn get_operators_reader<'b>(&self) -> Result<OperatorsReader<'b>>
    where
        'a: 'b,
    {
        let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
        Self::skip_locals(&mut reader)?;
        let pos = reader.position;
        Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos))
    }
}

pub struct LocalsReader<'a> {
    reader: BinaryReader<'a>,
    count: u32,
}

impl<'a> LocalsReader<'a> {
    pub fn get_count(&self) -> u32 {
        self.count
    }

    pub fn read(&mut self) -> Result<(u32, Type)> {
        let count = self.reader.read_var_u32()?;
        let value_type = self.reader.read_type()?;
        Ok((count, value_type))
    }
}

pub struct CodeSectionReader<'a> {
    reader: BinaryReader<'a>,
    count: u32,
}

impl<'a> IntoIterator for LocalsReader<'a> {
    type Item = Result<(u32, Type)>;
    type IntoIter = LocalsIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        let count = self.count;
        LocalsIterator {
            reader: self,
            left: count,
            err: false,
        }
    }
}

pub struct LocalsIterator<'a> {
    reader: LocalsReader<'a>,
    left: u32,
    err: bool,
}

impl<'a> Iterator for LocalsIterator<'a> {
    type Item = Result<(u32, Type)>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.err || self.left == 0 {
            return None;
        }
        let result = self.reader.read();
        self.err = result.is_err();
        self.left -= 1;
        Some(result)
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        let count = self.reader.get_count() as usize;
        (count, Some(count))
    }
}

impl<'a> CodeSectionReader<'a> {
    pub fn new(data: &'a [u8], offset: usize) -> Result<CodeSectionReader<'a>> {
        let mut reader = BinaryReader::new_with_offset(data, offset);
        let count = reader.read_var_u32()?;
        Ok(CodeSectionReader { reader, count })
    }

    pub fn original_position(&self) -> usize {
        self.reader.original_position()
    }

    pub fn get_count(&self) -> u32 {
        self.count
    }

    fn verify_body_end(&self, end: usize) -> Result<()> {
        if self.reader.buffer.len() < end {
            return Err(BinaryReaderError {
                message: "Function body extends past end of the code section",
                offset: self.reader.original_offset + self.reader.buffer.len(),
            });
        }
        Ok(())
    }

    /// Reads content of the code section.
    ///
    /// # Examples
    /// ```
    /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
    /// #     0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
    /// #     0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
    /// use wasmparser::ModuleReader;
    /// let mut reader = ModuleReader::new(data).expect("module reader");
    /// let section = reader.read().expect("type section");
    /// let section = reader.read().expect("function section");
    /// let section = reader.read().expect("code section");
    /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
    /// for _ in 0..code_reader.get_count() {
    ///     let body = code_reader.read().expect("function body");
    ///     let mut binary_reader = body.get_binary_reader();
    ///     assert!(binary_reader.read_local_count().expect("local count") == 0);
    ///     let op = binary_reader.read_operator().expect("first operator");
    ///     println!("First operator: {:?}", op);
    /// }
    /// ```
    pub fn read<'b>(&mut self) -> Result<FunctionBody<'b>>
    where
        'a: 'b,
    {
        let size = self.reader.read_var_u32()? as usize;
        let body_start = self.reader.position;
        let body_end = body_start + size;
        self.verify_body_end(body_end)?;
        self.reader.skip_to(body_end);
        Ok(FunctionBody {
            offset: self.reader.original_offset + body_start,
            data: &self.reader.buffer[body_start..body_end],
        })
    }
}

impl<'a> SectionReader for CodeSectionReader<'a> {
    type Item = FunctionBody<'a>;
    fn read(&mut self) -> Result<Self::Item> {
        CodeSectionReader::read(self)
    }
    fn eof(&self) -> bool {
        self.reader.eof()
    }
    fn original_position(&self) -> usize {
        CodeSectionReader::original_position(self)
    }
}

impl<'a> SectionWithLimitedItems for CodeSectionReader<'a> {
    fn get_count(&self) -> u32 {
        CodeSectionReader::get_count(self)
    }
}

impl<'a> IntoIterator for CodeSectionReader<'a> {
    type Item = Result<FunctionBody<'a>>;
    type IntoIter = SectionIteratorLimited<CodeSectionReader<'a>>;

    /// Implements iterator over the code section.
    ///
    /// # Examples
    /// ```
    /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
    /// #     0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
    /// #     0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
    /// use wasmparser::ModuleReader;
    /// let mut reader = ModuleReader::new(data).expect("module reader");
    /// let section = reader.read().expect("type section");
    /// let section = reader.read().expect("function section");
    /// let section = reader.read().expect("code section");
    /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
    /// for body in code_reader {
    ///     let mut binary_reader = body.expect("b").get_binary_reader();
    ///     assert!(binary_reader.read_local_count().expect("local count") == 0);
    ///     let op = binary_reader.read_operator().expect("first operator");
    ///     println!("First operator: {:?}", op);
    /// }
    /// ```
    fn into_iter(self) -> Self::IntoIter {
        SectionIteratorLimited::new(self)
    }
}
<commit_msg>Add a way to build a `FunctionBody` using a raw byte buffer.<commit_after>/* Copyright 2018 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use super::{
    BinaryReader, BinaryReaderError, OperatorsReader, Result, SectionIteratorLimited,
    SectionReader, SectionWithLimitedItems, Type,
};

#[derive(Debug)]
pub struct FunctionBody<'a> {
    offset: usize,
    data: &'a [u8],
}

impl<'a> FunctionBody<'a> {
    pub fn new(offset: usize, data: &'a [u8]) -> Self {
        Self { offset, data }
    }

    pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
    where
        'a: 'b,
    {
        BinaryReader::new_with_offset(self.data, self.offset)
    }

    fn skip_locals(reader: &mut BinaryReader) -> Result<()> {
        let count = reader.read_var_u32()?;
        for _ in 0..count {
            reader.skip_var_32()?;
            reader.skip_type()?;
        }
        Ok(())
    }

    pub fn get_locals_reader<'b>(&self) -> Result<LocalsReader<'b>>
    where
        'a: 'b,
    {
        let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
        let count = reader.read_var_u32()?;
        Ok(LocalsReader { reader, count })
    }

    pub fn get_operators_reader<'b>(&self) -> Result<OperatorsReader<'b>>
    where
        'a: 'b,
    {
        let mut reader = BinaryReader::new_with_offset(self.data, self.offset);
        Self::skip_locals(&mut reader)?;
        let pos = reader.position;
        Ok(OperatorsReader::new(&self.data[pos..], self.offset + pos))
    }
}

pub struct LocalsReader<'a> {
    reader: BinaryReader<'a>,
    count: u32,
}

impl<'a> LocalsReader<'a> {
    pub fn get_count(&self) -> u32 {
        self.count
    }

    pub fn read(&mut self) -> Result<(u32, Type)> {
        let count = self.reader.read_var_u32()?;
        let value_type = self.reader.read_type()?;
        Ok((count, value_type))
    }
}

pub struct CodeSectionReader<'a> {
    reader: BinaryReader<'a>,
    count: u32,
}

impl<'a> IntoIterator for LocalsReader<'a> {
    type Item = Result<(u32, Type)>;
    type IntoIter = LocalsIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        let count = self.count;
        LocalsIterator {
            reader: self,
            left: count,
            err: false,
        }
    }
}

pub struct LocalsIterator<'a> {
    reader: LocalsReader<'a>,
    left: u32,
    err: bool,
}

impl<'a> Iterator for LocalsIterator<'a> {
    type Item = Result<(u32, Type)>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.err || self.left == 0 {
            return None;
        }
        let result = self.reader.read();
        self.err = result.is_err();
        self.left -= 1;
        Some(result)
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        let count = self.reader.get_count() as usize;
        (count, Some(count))
    }
}

impl<'a> CodeSectionReader<'a> {
    pub fn new(data: &'a [u8], offset: usize) -> Result<CodeSectionReader<'a>> {
        let mut reader = BinaryReader::new_with_offset(data, offset);
        let count = reader.read_var_u32()?;
        Ok(CodeSectionReader { reader, count })
    }

    pub fn original_position(&self) -> usize {
        self.reader.original_position()
    }

    pub fn get_count(&self) -> u32 {
        self.count
    }

    fn verify_body_end(&self, end: usize) -> Result<()> {
        if self.reader.buffer.len() < end {
            return Err(BinaryReaderError {
                message: "Function body extends past end of the code section",
                offset: self.reader.original_offset + self.reader.buffer.len(),
            });
        }
        Ok(())
    }

    /// Reads content of the code section.
    ///
    /// # Examples
    /// ```
    /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
    /// #     0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
    /// #     0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
    /// use wasmparser::ModuleReader;
    /// let mut reader = ModuleReader::new(data).expect("module reader");
    /// let section = reader.read().expect("type section");
    /// let section = reader.read().expect("function section");
    /// let section = reader.read().expect("code section");
    /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
    /// for _ in 0..code_reader.get_count() {
    ///     let body = code_reader.read().expect("function body");
    ///     let mut binary_reader = body.get_binary_reader();
    ///     assert!(binary_reader.read_local_count().expect("local count") == 0);
    ///     let op = binary_reader.read_operator().expect("first operator");
    ///     println!("First operator: {:?}", op);
    /// }
    /// ```
    pub fn read<'b>(&mut self) -> Result<FunctionBody<'b>>
    where
        'a: 'b,
    {
        let size = self.reader.read_var_u32()? as usize;
        let body_start = self.reader.position;
        let body_end = body_start + size;
        self.verify_body_end(body_end)?;
        self.reader.skip_to(body_end);
        Ok(FunctionBody {
            offset: self.reader.original_offset + body_start,
            data: &self.reader.buffer[body_start..body_end],
        })
    }
}

impl<'a> SectionReader for CodeSectionReader<'a> {
    type Item = FunctionBody<'a>;
    fn read(&mut self) -> Result<Self::Item> {
        CodeSectionReader::read(self)
    }
    fn eof(&self) -> bool {
        self.reader.eof()
    }
    fn original_position(&self) -> usize {
        CodeSectionReader::original_position(self)
    }
}

impl<'a> SectionWithLimitedItems for CodeSectionReader<'a> {
    fn get_count(&self) -> u32 {
        CodeSectionReader::get_count(self)
    }
}

impl<'a> IntoIterator for CodeSectionReader<'a> {
    type Item = Result<FunctionBody<'a>>;
    type IntoIter = SectionIteratorLimited<CodeSectionReader<'a>>;

    /// Implements iterator over the code section.
    ///
    /// # Examples
    /// ```
    /// # let data: &[u8] = &[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
    /// #     0x01, 0x4, 0x01, 0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
    /// #     0x0a, 0x05, 0x01, 0x03, 0x00, 0x01, 0x0b];
    /// use wasmparser::ModuleReader;
    /// let mut reader = ModuleReader::new(data).expect("module reader");
    /// let section = reader.read().expect("type section");
    /// let section = reader.read().expect("function section");
    /// let section = reader.read().expect("code section");
    /// let mut code_reader = section.get_code_section_reader().expect("code section reader");
    /// for body in code_reader {
    ///     let mut binary_reader = body.expect("b").get_binary_reader();
    ///     assert!(binary_reader.read_local_count().expect("local count") == 0);
    ///     let op = binary_reader.read_operator().expect("first operator");
    ///     println!("First operator: {:?}", op);
    /// }
    /// ```
    fn into_iter(self) -> Self::IntoIter {
        SectionIteratorLimited::new(self)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

#![allow(missing_docs)]

use std::io;

use rr::{Name, RecordType};

#[cfg(feature = "openssl")]
use openssl::error::ErrorStack as SslErrorStack;
#[cfg(not(feature = "openssl"))]
use self::not_openssl::SslErrorStack;
#[cfg(feature = "ring")]
use ring::error::Unspecified;
#[cfg(not(feature = "ring"))]
use self::not_ring::Unspecified;

error_chain! {
    // The type defined for this error. These are the conventional
    // and recommended names, but they can be arbitrarily chosen.
    types {
        ProtoError, ProtoErrorKind, ProtoChainErr, ProtoResult;
    }

    // Automatic conversions between this error chain and other
    // error chains. In this case, it will e.g. generate an
    // `ErrorKind` variant called `Dist` which in turn contains
    // the `rustup_dist::ErrorKind`, with conversions from
    // `rustup_dist::Error`.
    //
    // This section can be empty.
    links {
    //   super::decode_error::Error, super::decode_error::ErrorKind, Decode;
    //   super::encode_error::Error, super::encode_error::ErrorKind, Encode;
    //   DnsSecError, ProtoErrorKind, DnsSec;
    }

    // Automatic conversions between this error chain and other
    // error types not defined by the `error_chain!`. These will be
    // boxed as the error cause and wrapped in a new error with,
    // in this case, the `ErrorKind::Temp` variant.
    //
    // This section can be empty.
    foreign_links {
      ::std::io::Error, Io, "io error";
      ::std::net::AddrParseError, AddrParseError, "network address parse error";
      ::std::num::ParseIntError, ParseIntError, "error parsing number";
      ::std::string::FromUtf8Error, FromUtf8Error, "utf8 conversion error";
      SslErrorStack, SSL, "ssl error";
      Unspecified, Ring, "ring error";
    }

    // Define additional `ErrorKind` variants. The syntax here is
    // the same as `quick_error!`, but the `from()` and `cause()`
    // syntax is not supported.
    errors {
      Canceled(c: ::futures::sync::oneshot::Canceled) {
        description("future was canceled")
        display("future was canceled: {:?}", c)
      }

      CharacterDataTooLong(len: usize) {
        description("char data length exceeds 255")
        display("char data length exceeds 255: {}", len)
      }

      DnsKeyProtocolNot3(value: u8) {
        description("dns key value unknown, must be 3")
        display("dns key value unknown, must be 3: {}", value)
      }

      DomainNameTooLong(len: usize) {
        description("name label data exceed 255")
        display("name label data exceed 255: {}", len)
      }

      EdnsNameNotRoot(found: ::rr::Name) {
        description("edns resource record label must be the root label (.)")
        display("edns resource record label must be the root label (.): {}", found)
      }

      LabelBytesTooLong(len: usize) {
        description("label bytes exceed 63")
        display("label bytes exceed 63: {}", len)
      }

      Message(msg: &'static str) {
        description(msg)
        display("{}", msg)
      }

      NoError {
        description("no error specified")
        display("no error specified")
      }

      NotAllBytesSent(sent: usize, expect: usize) {
        description("not all bytes were sent")
        display("not all bytes were sent: {}, expected: {}", sent, expect)
      }

      NotAllBytesReceived(received: usize, expect: usize) {
        description("not all bytes were recieved")
        display("not all bytes were recieved: {}, expected: {}", received, expect)
      }

      IncorrectMessageId(got: u16, expect: u16) {
        description("incorrectMessageId received")
        display("incorrectMessageId got: {}, expected: {}", got, expect)
      }

      IncorrectRDataLengthRead(read: usize, len: usize) {
        description("incorrect rdata length read")
        display("incorrect rdata length read: {} expected: {}", read, len)
      }

      Timeout {
        description("request timeout")
        display("request timed out")
      }

      UnknownAlgorithmTypeValue(value: u8) {
        description("algorithm type value unknown")
        display("algorithm type value unknown: {}", value)
      }

      UnknownDnsClassStr(value: String) {
        description("dns class string unknown")
        display("dns class string unknown: {}", value)
      }

      UnknownDnsClassValue(value: u16) {
        description("dns class value unknown")
        display("dns class value unknown: {}", value)
      }

      UnrecognizedLabelCode(value: u8) {
        description("unrecognized label code")
        display("unrecognized label code: {:b}", value)
      }

      UnrecognizedNsec3Flags(value: u8) {
        description("nsec3 flags should be 0b0000000*")
        display("nsec3 flags should be 0b0000000*: {:b}", value)
      }

      UnknownRecordTypeStr(value: String) {
        description("record type string unknown")
        display("record type string unknown: {}", value)
      }

      UnknownRecordTypeValue(value: u16) {
        description("record type value unknown")
        display("record type value unknown: {}", value)
      }

      // TODO: these are only necessary until TXT serialization stuff is moved
      EscapedCharOutsideCharData {
        description("escaped character outside character data")
        display("escaped character outside character data")
      }

      IllegalCharacter(ch: char) {
        description("illegal character input")
        display("illegal character input: {}", ch)
      }

      UnrecognizedChar(ch: char) {
        description("unrecognized character input")
        display("unrecognized character input: {}", ch)
      }

      BadEscapedData(string: String) {
        description("escaped data not recognized")
        display("escaped data not recognized: {}", string)
      }

      UnrecognizedOctet(octet: u32) {
        description("unrecognized octet")
        display("unrecognized octet: {:x}", octet)
      }

      UnclosedQuotedString {
        description("unclosed quoted string")
        display("unclosed quoted string")
      }

      UnclosedList {
        description("unclosed list, missing ')'")
        display("unclosed list, missing ')'")
      }

      UnrecognizedDollar(string: String) {
        description("unrecognized dollar content")
        display("unrecognized dollar content: {}", string)
      }

      EOF {
        description("unexpected end of input")
        display("unexpected end of input")
      }

      IllegalState(string: &'static str) {
        description("illegal state")
        display("illegal state: {}", string)
      }

      MissingToken(string: String) {
        description("token is missing")
        display("token is missing: {}", string)
      }

      CharToIntError(ch: char) {
        description("invalid numerical character")
        display("invalid numerical character: {}", ch)
      }

      ParseTimeError(string: String) {
        description("invalid time string")
        display("invalid time string: {}", string)
      }

      RrsigsNotPresent(name: Name, record_type: RecordType) {
        description("rrsigs are not present for record set")
        display("rrsigs are not present for record set name: {} record_type: {}", name, record_type)
      }
    }
}

#[cfg(not(feature = "openssl"))]
pub mod not_openssl {
    use std;

    #[derive(Debug)]
    pub struct SslErrorStack;

    impl std::fmt::Display for SslErrorStack {
        fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
            Ok(())
        }
    }

    impl std::error::Error for SslErrorStack {
        fn description(&self) -> &str {
            "openssl feature not enabled"
        }
    }
}

#[cfg(not(feature = "ring"))]
pub mod not_ring {
    use std;

    #[derive(Debug)]
    pub struct Unspecified;

    impl std::fmt::Display for Unspecified {
        fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
            Ok(())
        }
    }

    impl std::error::Error for Unspecified {
        fn description(&self) -> &str {
            "ring feature not enabled"
        }
    }
}

impl From<ProtoError> for io::Error {
    fn from(e: ProtoError) -> Self {
        let error_kind = match e.kind() {
            &ProtoErrorKind::Timeout => io::ErrorKind::TimedOut,
            _ => io::ErrorKind::Other,
        };

        io::Error::new(error_kind, format!("ProtoError: {}", e))
    }
}

impl Clone for ProtoErrorKind {
    fn clone(&self) -> Self {
        match self {
            &ProtoErrorKind::AddrParseError => ProtoErrorKind::AddrParseError,
            &ProtoErrorKind::Canceled(ref c) => ProtoErrorKind::Canceled(c.clone()),
            &ProtoErrorKind::CharacterDataTooLong(len) => ProtoErrorKind::CharacterDataTooLong(len),
            &ProtoErrorKind::DnsKeyProtocolNot3(value) => ProtoErrorKind::DnsKeyProtocolNot3(value),
            &ProtoErrorKind::DomainNameTooLong(len) => ProtoErrorKind::DomainNameTooLong(len),
            &ProtoErrorKind::EdnsNameNotRoot(ref found) => ProtoErrorKind::EdnsNameNotRoot(
                found.clone(),
            ),
            &ProtoErrorKind::FromUtf8Error => ProtoErrorKind::FromUtf8Error,
            &ProtoErrorKind::Io => ProtoErrorKind::Io,
            &ProtoErrorKind::IncorrectMessageId(got, expect) => {
                ProtoErrorKind::IncorrectMessageId(got, expect)
            }
            &ProtoErrorKind::IncorrectRDataLengthRead(read, len) => {
                ProtoErrorKind::IncorrectRDataLengthRead(read, len)
            }
            &ProtoErrorKind::LabelBytesTooLong(len) => ProtoErrorKind::LabelBytesTooLong(len),
            &ProtoErrorKind::Message(msg) => ProtoErrorKind::Message(msg),
            &ProtoErrorKind::Msg(ref string) => ProtoErrorKind::Msg(string.clone()),
            &ProtoErrorKind::NoError => ProtoErrorKind::NoError,
            &ProtoErrorKind::NotAllBytesSent(sent, expect) => {
                ProtoErrorKind::NotAllBytesSent(sent, expect)
            }
            &ProtoErrorKind::NotAllBytesReceived(received, expect) => {
                ProtoErrorKind::NotAllBytesReceived(received, expect)
            }
            &ProtoErrorKind::ParseIntError => ProtoErrorKind::ParseIntError,
            &ProtoErrorKind::Timeout => ProtoErrorKind::Timeout,
            &ProtoErrorKind::UnknownAlgorithmTypeValue(value) => {
                ProtoErrorKind::UnknownAlgorithmTypeValue(value)
            }
            &ProtoErrorKind::UnknownDnsClassStr(ref value) => ProtoErrorKind::UnknownDnsClassStr(
                value.clone(),
            ),
            &ProtoErrorKind::UnknownDnsClassValue(value) => ProtoErrorKind::UnknownDnsClassValue(
                value,
            ),
            &ProtoErrorKind::UnrecognizedLabelCode(value) => {
                ProtoErrorKind::UnrecognizedLabelCode(value)
            }
            &ProtoErrorKind::UnrecognizedNsec3Flags(value) => {
                ProtoErrorKind::UnrecognizedNsec3Flags(value)
            }
            &ProtoErrorKind::UnknownRecordTypeStr(ref value) => {
                ProtoErrorKind::UnknownRecordTypeStr(value.clone())
            }
            &ProtoErrorKind::UnknownRecordTypeValue(value) => {
                ProtoErrorKind::UnknownRecordTypeValue(value)
            }
            &ProtoErrorKind::EscapedCharOutsideCharData => {
                ProtoErrorKind::EscapedCharOutsideCharData
            }
            &ProtoErrorKind::IllegalCharacter(ch) => ProtoErrorKind::IllegalCharacter(ch),
            &ProtoErrorKind::UnrecognizedChar(ch) => ProtoErrorKind::UnrecognizedChar(ch),
            &ProtoErrorKind::BadEscapedData(ref string) => ProtoErrorKind::BadEscapedData(
                string.clone(),
            ),
            &ProtoErrorKind::UnrecognizedOctet(octet) => ProtoErrorKind::UnrecognizedOctet(octet),
            &ProtoErrorKind::UnclosedQuotedString => ProtoErrorKind::UnclosedQuotedString,
            &ProtoErrorKind::UnclosedList => ProtoErrorKind::UnclosedList,
            &ProtoErrorKind::UnrecognizedDollar(ref string) => ProtoErrorKind::UnrecognizedDollar(
                string.clone(),
            ),
            &ProtoErrorKind::EOF => ProtoErrorKind::EOF,
            &ProtoErrorKind::IllegalState(string) => ProtoErrorKind::IllegalState(string),
            &ProtoErrorKind::MissingToken(ref string) => ProtoErrorKind::MissingToken(
                string.clone(),
            ),
            &ProtoErrorKind::CharToIntError(ch) => ProtoErrorKind::CharToIntError(ch),
            &ProtoErrorKind::ParseTimeError(ref string) => ProtoErrorKind::ParseTimeError(
                string.clone(),
            ),
            &ProtoErrorKind::Ring => ProtoErrorKind::Ring,
            &ProtoErrorKind::SSL => ProtoErrorKind::SSL,
            &ProtoErrorKind::RrsigsNotPresent(ref name, ref record_type) => ProtoErrorKind::RrsigsNotPresent(
                name.clone(),
                *record_type,
            ),
        }
    }
}

// TODO: replace this when https://github.com/rust-lang-nursery/error-chain/pull/163 is merged
impl Clone for ProtoError {
    fn clone(&self) -> Self {
        let cloned_kind: ProtoErrorKind = self.0.clone();

        // sadly need to convert the inner error...

        let inner_error: Option<Box<::std::error::Error + Send + 'static>> =
            (&self.1).0.as_ref().map(|e| {
                Box::new(ProtoError::from(ProtoErrorKind::Msg(format!("{}", e)))) as
                    Box<::std::error::Error + Send + 'static>
            });
        ProtoError(cloned_kind, (inner_error, (self.1).1.clone()))
    }
}<commit_msg>remove unused proto errors<commit_after>// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

#![allow(missing_docs)]

use std::io;

use rr::{Name, RecordType};

#[cfg(feature = "openssl")]
use openssl::error::ErrorStack as SslErrorStack;
#[cfg(not(feature = "openssl"))]
use self::not_openssl::SslErrorStack;
#[cfg(feature = "ring")]
use ring::error::Unspecified;
#[cfg(not(feature = "ring"))]
use self::not_ring::Unspecified;

error_chain! {
    // The type defined for this error. These are the conventional
    // and recommended names, but they can be arbitrarily chosen.
    types {
        ProtoError, ProtoErrorKind, ProtoChainErr, ProtoResult;
    }

    // Automatic conversions between this error chain and other
    // error chains. In this case, it will e.g. generate an
    // `ErrorKind` variant called `Dist` which in turn contains
    // the `rustup_dist::ErrorKind`, with conversions from
    // `rustup_dist::Error`.
    //
    // This section can be empty.
    links {
    //   super::decode_error::Error, super::decode_error::ErrorKind, Decode;
    //   super::encode_error::Error, super::encode_error::ErrorKind, Encode;
    //   DnsSecError, ProtoErrorKind, DnsSec;
    }

    // Automatic conversions between this error chain and other
    // error types not defined by the `error_chain!`. These will be
    // boxed as the error cause and wrapped in a new error with,
    // in this case, the `ErrorKind::Temp` variant.
    //
    // This section can be empty.
    foreign_links {
      ::std::io::Error, Io, "io error";
      ::std::net::AddrParseError, AddrParseError, "network address parse error";
      ::std::num::ParseIntError, ParseIntError, "error parsing number";
      ::std::string::FromUtf8Error, FromUtf8Error, "utf8 conversion error";
      SslErrorStack, SSL, "ssl error";
      Unspecified, Ring, "ring error";
    }

    // Define additional `ErrorKind` variants. The syntax here is
    // the same as `quick_error!`, but the `from()` and `cause()`
    // syntax is not supported.
    errors {
      Canceled(c: ::futures::sync::oneshot::Canceled) {
        description("future was canceled")
        display("future was canceled: {:?}", c)
      }

      CharacterDataTooLong(len: usize) {
        description("char data length exceeds 255")
        display("char data length exceeds 255: {}", len)
      }

      DnsKeyProtocolNot3(value: u8) {
        description("dns key value unknown, must be 3")
        display("dns key value unknown, must be 3: {}", value)
      }

      DomainNameTooLong(len: usize) {
        description("name label data exceed 255")
        display("name label data exceed 255: {}", len)
      }

      EdnsNameNotRoot(found: ::rr::Name) {
        description("edns resource record label must be the root label (.)")
        display("edns resource record label must be the root label (.): {}", found)
      }

      LabelBytesTooLong(len: usize) {
        description("label bytes exceed 63")
        display("label bytes exceed 63: {}", len)
      }

      Message(msg: &'static str) {
        description(msg)
        display("{}", msg)
      }

      NoError {
        description("no error specified")
        display("no error specified")
      }

      IncorrectRDataLengthRead(read: usize, len: usize) {
        description("incorrect rdata length read")
        display("incorrect rdata length read: {} expected: {}", read, len)
      }

      Timeout {
        description("request timeout")
        display("request timed out")
      }

      UnknownAlgorithmTypeValue(value: u8) {
        description("algorithm type value unknown")
        display("algorithm type value unknown: {}", value)
      }

      UnknownDnsClassStr(value: String) {
        description("dns class string unknown")
        display("dns class string unknown: {}", value)
      }

      UnknownDnsClassValue(value: u16) {
        description("dns class value unknown")
        display("dns class value unknown: {}", value)
      }

      UnrecognizedLabelCode(value: u8) {
        description("unrecognized label code")
        display("unrecognized label code: {:b}", value)
      }

      UnrecognizedNsec3Flags(value: u8) {
        description("nsec3 flags should be 0b0000000*")
        display("nsec3 flags should be 0b0000000*: {:b}", value)
      }

      UnknownRecordTypeStr(value: String) {
        description("record type string unknown")
        display("record type string unknown: {}", value)
      }

      UnknownRecordTypeValue(value: u16) {
        description("record type value unknown")
        display("record type value unknown: {}", value)
      }

      RrsigsNotPresent(name: Name, record_type: RecordType) {
        description("rrsigs are not present for record set")
        display("rrsigs are not present for record set name: {} record_type: {}", name, record_type)
      }
    }
}

#[cfg(not(feature = "openssl"))]
pub mod not_openssl {
    use std;

    #[derive(Debug)]
    pub struct SslErrorStack;

    impl std::fmt::Display for SslErrorStack {
        fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
            Ok(())
        }
    }

    impl std::error::Error for SslErrorStack {
        fn description(&self) -> &str {
            "openssl feature not enabled"
        }
    }
}

#[cfg(not(feature = "ring"))]
pub mod not_ring {
    use std;

    #[derive(Debug)]
    pub struct Unspecified;

    impl std::fmt::Display for Unspecified {
        fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
            Ok(())
        }
    }

    impl std::error::Error for Unspecified {
        fn description(&self) -> &str {
            "ring feature not enabled"
        }
    }
}

impl From<ProtoError> for io::Error {
    fn from(e: ProtoError) -> Self {
        let error_kind = match e.kind() {
            &ProtoErrorKind::Timeout => io::ErrorKind::TimedOut,
            _ => io::ErrorKind::Other,
        };

        io::Error::new(error_kind, format!("ProtoError: {}", e))
    }
}

impl Clone for ProtoErrorKind {
    fn clone(&self) -> Self {
        match self {
            &ProtoErrorKind::AddrParseError => ProtoErrorKind::AddrParseError,
            &ProtoErrorKind::Canceled(ref c) => ProtoErrorKind::Canceled(c.clone()),
            &ProtoErrorKind::CharacterDataTooLong(len) => ProtoErrorKind::CharacterDataTooLong(len),
            &ProtoErrorKind::DnsKeyProtocolNot3(value) => ProtoErrorKind::DnsKeyProtocolNot3(value),
            &ProtoErrorKind::DomainNameTooLong(len) => ProtoErrorKind::DomainNameTooLong(len),
            &ProtoErrorKind::EdnsNameNotRoot(ref found) => ProtoErrorKind::EdnsNameNotRoot(
                found.clone(),
            ),
            &ProtoErrorKind::FromUtf8Error => ProtoErrorKind::FromUtf8Error,
            &ProtoErrorKind::Io => ProtoErrorKind::Io,
            &ProtoErrorKind::IncorrectRDataLengthRead(read, len) => {
                ProtoErrorKind::IncorrectRDataLengthRead(read, len)
            }
            &ProtoErrorKind::LabelBytesTooLong(len) => ProtoErrorKind::LabelBytesTooLong(len),
            &ProtoErrorKind::Message(msg) => ProtoErrorKind::Message(msg),
            &ProtoErrorKind::Msg(ref string) => ProtoErrorKind::Msg(string.clone()),
            &ProtoErrorKind::NoError => ProtoErrorKind::NoError,
            &ProtoErrorKind::ParseIntError => ProtoErrorKind::ParseIntError,
            &ProtoErrorKind::Timeout => ProtoErrorKind::Timeout,
            &ProtoErrorKind::UnknownAlgorithmTypeValue(value) => {
                ProtoErrorKind::UnknownAlgorithmTypeValue(value)
            }
            &ProtoErrorKind::UnknownDnsClassStr(ref value) => ProtoErrorKind::UnknownDnsClassStr(
                value.clone(),
            ),
            &ProtoErrorKind::UnknownDnsClassValue(value) => ProtoErrorKind::UnknownDnsClassValue(
                value,
            ),
            &ProtoErrorKind::UnrecognizedLabelCode(value) => {
                ProtoErrorKind::UnrecognizedLabelCode(value)
            }
            &ProtoErrorKind::UnrecognizedNsec3Flags(value) => {
                ProtoErrorKind::UnrecognizedNsec3Flags(value)
            }
            &ProtoErrorKind::UnknownRecordTypeStr(ref value) => {
                ProtoErrorKind::UnknownRecordTypeStr(value.clone())
            }
            &ProtoErrorKind::UnknownRecordTypeValue(value) => {
                ProtoErrorKind::UnknownRecordTypeValue(value)
            }
            &ProtoErrorKind::Ring => ProtoErrorKind::Ring,
            &ProtoErrorKind::SSL => ProtoErrorKind::SSL,
            &ProtoErrorKind::RrsigsNotPresent(ref name, ref record_type) => {
                ProtoErrorKind::RrsigsNotPresent(name.clone(), *record_type)
            }
        }
    }
}

// TODO: replace this when https://github.com/rust-lang-nursery/error-chain/pull/163 is merged
impl Clone for ProtoError {
    fn clone(&self) -> Self {
        let cloned_kind: ProtoErrorKind = self.0.clone();

        // sadly need to convert the inner error...

        let inner_error: Option<Box<::std::error::Error + Send + 'static>> =
            (&self.1).0.as_ref().map(|e| {
                Box::new(ProtoError::from(ProtoErrorKind::Msg(format!("{}", e)))) as
                    Box<::std::error::Error + Send + 'static>
            });
        ProtoError(cloned_kind, (inner_error, (self.1).1.clone()))
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;

use SafeDeref;
use VulkanObject;
use buffer::BufferAccess;
use command_buffer::submit::SubmitAnyBuilder;
use command_buffer::submit::SubmitCommandBufferBuilder;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessError;
use sync::AccessFlagBits;
use sync::FlushError;
use sync::GpuFuture;
use sync::NowFuture;
use sync::PipelineStages;
use sync::now;

pub unsafe trait CommandBuffer: DeviceOwned {
    /// The command pool of the command buffer.
    type PoolAlloc;

    /// Returns the underlying `UnsafeCommandBuffer` of this command buffer.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::PoolAlloc>;

    /*/// Returns the queue family of the command buffer.
    #[inline]
    fn queue_family(&self) -> QueueFamily
        where Self::PoolAlloc: CommandPoolAlloc
    {
        self.inner().queue_family()
    }*/

    /// Checks whether this command buffer is allowed to be submitted after the `future` and on
    /// the given queue, and if so locks it.
    ///
    /// If you call this function, then you should call `unlock` afterwards.
    // TODO: require `&mut self` instead, but this has some consequences on other parts of the lib
    fn lock_submit(&self, future: &GpuFuture, queue: &Queue) -> Result<(), CommandBufferExecError>;

    /// Unlocks the command buffer. Should be called once for each call to `lock_submit`.
    ///
    /// # Safety
    ///
    /// Must not be called if you haven't called `lock_submit` before.
    // TODO: require `&mut self` instead, but this has some consequences on other parts of the lib
    unsafe fn unlock(&self);

    /// Executes this command buffer on a queue.
    ///
    /// This function returns an object that implements the `GpuFuture` trait. See the
    /// documentation of the `sync` module for more information.
    ///
    /// The command buffer is not actually executed until you call `flush()` on the object.
    /// You are encouraged to chain together as many futures as possible before calling `flush()`,
    /// and call `.then_signal_future()` before doing so. Note however that once you called
    /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
    ///
    /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
    /// > concrete type.
    ///
    /// > **Note**: This is just a shortcut for `execute_after(vulkano::sync::now(), queue)`.
    ///
    /// # Panic
    ///
    /// Panics if the device of the command buffer is not the same as the device of the future.
    #[inline]
    fn execute(self, queue: Arc<Queue>)
               -> Result<CommandBufferExecFuture<NowFuture, Self>, CommandBufferExecError>
        where Self: Sized + 'static
    {
        let device = queue.device().clone();
        self.execute_after(now(device), queue)
    }

    /// Executes the command buffer after an existing future.
    ///
    /// This function returns an object that implements the `GpuFuture` trait. See the
    /// documentation of the `sync` module for more information.
    ///
    /// The command buffer is not actually executed until you call `flush()` on the object.
    /// You are encouraged to chain together as many futures as possible before calling `flush()`,
    /// and call `.then_signal_future()` before doing so. Note however that once you called
    /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
    ///
    /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
    /// > concrete type.
    ///
    /// This function requires the `'static` lifetime to be on the command buffer. This is because
    /// this function returns a `CommandBufferExecFuture` whose job is to lock resources and keep
    /// them alive while they are in use by the GPU. If `'static` wasn't required, you could call
    /// `std::mem::forget` on that object and "unlock" these resources. For more information about
    /// this problem, search the web for "rust thread scoped leakpocalypse".
    ///
    /// # Panic
    ///
    /// Panics if the device of the command buffer is not the same as the device of the future.
    #[inline]
    fn execute_after<F>(self, future: F, queue: Arc<Queue>)
                        -> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError>
        where Self: Sized + 'static,
              F: GpuFuture
    {
        assert_eq!(self.device().internal_object(),
                   future.device().internal_object());

        if !future.queue_change_allowed() {
            assert!(future.queue().unwrap().is_same(&queue));
        }

        self.lock_submit(&future, &queue)?;

        Ok(CommandBufferExecFuture {
               previous: future,
               command_buffer: self,
               queue: queue,
               submitted: Mutex::new(false),
               finished: AtomicBool::new(false),
           })
    }

    fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
                           -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;

    fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool,
                          queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;

    // FIXME: lots of other methods
}

/// Turns a command buffer builder into a real command buffer.
pub unsafe trait CommandBufferBuild {
    /// The type of the built command buffer.
    type Out;
    /// Error that can be returned when building.
    type Err;

    /// Builds the command buffer.
    fn build(self) -> Result<Self::Out, Self::Err>;
}

unsafe impl<T> CommandBuffer for T
    where T: SafeDeref,
          T::Target: CommandBuffer
{
    type PoolAlloc = <T::Target as CommandBuffer>::PoolAlloc;

    #[inline]
    fn inner(&self) -> &UnsafeCommandBuffer<Self::PoolAlloc> {
        (**self).inner()
    }

    #[inline]
    fn lock_submit(&self, future: &GpuFuture, queue: &Queue) -> Result<(), CommandBufferExecError> {
        (**self).lock_submit(future, queue)
    }

    #[inline]
    unsafe fn unlock(&self) {
        (**self).unlock();
    }

    #[inline]
    fn check_buffer_access(
        &self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
        -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        (**self).check_buffer_access(buffer, exclusive, queue)
    }

    #[inline]
    fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool,
                          queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        (**self).check_image_access(image, layout, exclusive, queue)
    }
}

/// Represents a command buffer being executed by the GPU and the moment when the execution
/// finishes.
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    previous: F,
    command_buffer: Cb,
    queue: Arc<Queue>,
    // True if the command buffer has already been submitted.
    // If flush is called multiple times, we want to block so that only one flushing is executed.
    // Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
    submitted: Mutex<bool>,
    finished: AtomicBool,
}

unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    #[inline]
    fn cleanup_finished(&mut self) {
        self.previous.cleanup_finished();
    }

    unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
        Ok(match self.previous.build_submission()? {
               SubmitAnyBuilder::Empty => {
                   let mut builder = SubmitCommandBufferBuilder::new();
                   builder.add_command_buffer(self.command_buffer.inner());
                   SubmitAnyBuilder::CommandBuffer(builder)
               },
               SubmitAnyBuilder::SemaphoresWait(sem) => {
                   let mut builder: SubmitCommandBufferBuilder = sem.into();
                   builder.add_command_buffer(self.command_buffer.inner());
                   SubmitAnyBuilder::CommandBuffer(builder)
               },
               SubmitAnyBuilder::CommandBuffer(mut builder) => {
                   // FIXME: add pipeline barrier
                   builder.add_command_buffer(self.command_buffer.inner());
                   SubmitAnyBuilder::CommandBuffer(builder)
               },
               SubmitAnyBuilder::QueuePresent(_) |
               SubmitAnyBuilder::BindSparse(_) => {
                   unimplemented!() // TODO:
                /*present.submit();     // TODO: wrong
                let mut builder = SubmitCommandBufferBuilder::new();
                builder.add_command_buffer(self.command_buffer.inner());
                SubmitAnyBuilder::CommandBuffer(builder)*/
               },
           })
    }

    #[inline]
    fn flush(&self) -> Result<(), FlushError> {
        unsafe {
            let mut submitted = self.submitted.lock().unwrap();
            if *submitted {
                return Ok(());
            }

            let queue = self.queue.clone();

            match self.build_submission()? {
                SubmitAnyBuilder::Empty => {},
                SubmitAnyBuilder::CommandBuffer(builder) => {
                    builder.submit(&queue)?;
                },
                _ => unreachable!(),
            };

            // Only write `true` here in order to try again next time if we failed to submit.
            *submitted = true;
            Ok(())
        }
    }

    #[inline]
    unsafe fn signal_finished(&self) {
        if self.finished.swap(true, Ordering::SeqCst) == false {
            self.command_buffer.unlock();
        }

        self.previous.signal_finished();
    }

    #[inline]
    fn queue_change_allowed(&self) -> bool {
        false
    }

    #[inline]
    fn queue(&self) -> Option<Arc<Queue>> {
        Some(self.queue.clone())
    }

    #[inline]
    fn check_buffer_access(
        &self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
        -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        match self.command_buffer
            .check_buffer_access(buffer, exclusive, queue) {
            Ok(v) => Ok(v),
            Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
            Err(AccessCheckError::Unknown) => {
                self.previous.check_buffer_access(buffer, exclusive, queue)
            },
        }
    }

    #[inline]
    fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool,
                          queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        match self.command_buffer
            .check_image_access(image, layout, exclusive, queue) {
            Ok(v) => Ok(v),
            Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
            Err(AccessCheckError::Unknown) => {
                self.previous
                    .check_image_access(image, layout, exclusive, queue)
            },
        }
    }
}

unsafe impl<F, Cb> DeviceOwned for CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.command_buffer.device()
    }
}

impl<F, Cb> Drop for CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    fn drop(&mut self) {
        unsafe {
            if !*self.finished.get_mut() {
                // TODO: handle errors?
                self.flush().unwrap();
                // Block until the queue finished.
                self.queue.wait().unwrap();
                self.command_buffer.unlock();
                self.previous.signal_finished();
            }
        }
    }
}

/// Error that can happen when attempting to execute a command buffer.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CommandBufferExecError {
    /// Access to a resource has been denied.
    AccessError(AccessError),

    /// The command buffer or one of the secondary command buffers it executes was created with the
    /// "one time submit" flag, but has already been submitted it the past.
    OneTimeSubmitAlreadySubmitted,

    /// The command buffer or one of the secondary command buffers it executes is already in use by
    /// the GPU and was not created with the "concurrent" flag.
    ExclusiveAlreadyInUse,

    // TODO: missing entries (eg. wrong queue family, secondary command buffer)
}

impl error::Error for CommandBufferExecError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CommandBufferExecError::AccessError(_) => {
                "access to a resource has been denied"
            },
            CommandBufferExecError::OneTimeSubmitAlreadySubmitted => {
                "the command buffer or one of the secondary command buffers it executes was \
                 created with the \"one time submit\" flag, but has already been submitted it \
                 the past"
            },
            CommandBufferExecError::ExclusiveAlreadyInUse => {
                "the command buffer or one of the secondary command buffers it executes is \
                 already in use by the GPU and was not created with the \"concurrent\" flag"
            },
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CommandBufferExecError::AccessError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for CommandBufferExecError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<AccessError> for CommandBufferExecError {
    #[inline]
    fn from(err: AccessError) -> CommandBufferExecError {
        CommandBufferExecError::AccessError(err)
    }
}
<commit_msg>Remove some TODOs (#812)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;

use SafeDeref;
use VulkanObject;
use buffer::BufferAccess;
use command_buffer::submit::SubmitAnyBuilder;
use command_buffer::submit::SubmitCommandBufferBuilder;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessError;
use sync::AccessFlagBits;
use sync::FlushError;
use sync::GpuFuture;
use sync::NowFuture;
use sync::PipelineStages;
use sync::now;

pub unsafe trait CommandBuffer: DeviceOwned {
    /// The command pool of the command buffer.
    type PoolAlloc;

    /// Returns the underlying `UnsafeCommandBuffer` of this command buffer.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::PoolAlloc>;

    /*/// Returns the queue family of the command buffer.
    #[inline]
    fn queue_family(&self) -> QueueFamily
        where Self::PoolAlloc: CommandPoolAlloc
    {
        self.inner().queue_family()
    }*/

    /// Checks whether this command buffer is allowed to be submitted after the `future` and on
    /// the given queue, and if so locks it.
    ///
    /// If you call this function, then you should call `unlock` afterwards.
    fn lock_submit(&self, future: &GpuFuture, queue: &Queue) -> Result<(), CommandBufferExecError>;

    /// Unlocks the command buffer. Should be called once for each call to `lock_submit`.
    ///
    /// # Safety
    ///
    /// Must not be called if you haven't called `lock_submit` before.
    unsafe fn unlock(&self);

    /// Executes this command buffer on a queue.
    ///
    /// This function returns an object that implements the `GpuFuture` trait. See the
    /// documentation of the `sync` module for more information.
    ///
    /// The command buffer is not actually executed until you call `flush()` on the object.
    /// You are encouraged to chain together as many futures as possible before calling `flush()`,
    /// and call `.then_signal_future()` before doing so. Note however that once you called
    /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
    ///
    /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
    /// > concrete type.
    ///
    /// > **Note**: This is just a shortcut for `execute_after(vulkano::sync::now(), queue)`.
    ///
    /// # Panic
    ///
    /// Panics if the device of the command buffer is not the same as the device of the future.
    #[inline]
    fn execute(self, queue: Arc<Queue>)
               -> Result<CommandBufferExecFuture<NowFuture, Self>, CommandBufferExecError>
        where Self: Sized + 'static
    {
        let device = queue.device().clone();
        self.execute_after(now(device), queue)
    }

    /// Executes the command buffer after an existing future.
    ///
    /// This function returns an object that implements the `GpuFuture` trait. See the
    /// documentation of the `sync` module for more information.
    ///
    /// The command buffer is not actually executed until you call `flush()` on the object.
    /// You are encouraged to chain together as many futures as possible before calling `flush()`,
    /// and call `.then_signal_future()` before doing so. Note however that once you called
    /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
    ///
    /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
    /// > concrete type.
    ///
    /// This function requires the `'static` lifetime to be on the command buffer. This is because
    /// this function returns a `CommandBufferExecFuture` whose job is to lock resources and keep
    /// them alive while they are in use by the GPU. If `'static` wasn't required, you could call
    /// `std::mem::forget` on that object and "unlock" these resources. For more information about
    /// this problem, search the web for "rust thread scoped leakpocalypse".
    ///
    /// # Panic
    ///
    /// Panics if the device of the command buffer is not the same as the device of the future.
    #[inline]
    fn execute_after<F>(self, future: F, queue: Arc<Queue>)
                        -> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError>
        where Self: Sized + 'static,
              F: GpuFuture
    {
        assert_eq!(self.device().internal_object(),
                   future.device().internal_object());

        if !future.queue_change_allowed() {
            assert!(future.queue().unwrap().is_same(&queue));
        }

        self.lock_submit(&future, &queue)?;

        Ok(CommandBufferExecFuture {
               previous: future,
               command_buffer: self,
               queue: queue,
               submitted: Mutex::new(false),
               finished: AtomicBool::new(false),
           })
    }

    fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
                           -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;

    fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool,
                          queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;

    // FIXME: lots of other methods
}

/// Turns a command buffer builder into a real command buffer.
pub unsafe trait CommandBufferBuild {
    /// The type of the built command buffer.
    type Out;
    /// Error that can be returned when building.
    type Err;

    /// Builds the command buffer.
    fn build(self) -> Result<Self::Out, Self::Err>;
}

unsafe impl<T> CommandBuffer for T
    where T: SafeDeref,
          T::Target: CommandBuffer
{
    type PoolAlloc = <T::Target as CommandBuffer>::PoolAlloc;

    #[inline]
    fn inner(&self) -> &UnsafeCommandBuffer<Self::PoolAlloc> {
        (**self).inner()
    }

    #[inline]
    fn lock_submit(&self, future: &GpuFuture, queue: &Queue) -> Result<(), CommandBufferExecError> {
        (**self).lock_submit(future, queue)
    }

    #[inline]
    unsafe fn unlock(&self) {
        (**self).unlock();
    }

    #[inline]
    fn check_buffer_access(
        &self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
        -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        (**self).check_buffer_access(buffer, exclusive, queue)
    }

    #[inline]
    fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool,
                          queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        (**self).check_image_access(image, layout, exclusive, queue)
    }
}

/// Represents a command buffer being executed by the GPU and the moment when the execution
/// finishes.
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    previous: F,
    command_buffer: Cb,
    queue: Arc<Queue>,
    // True if the command buffer has already been submitted.
    // If flush is called multiple times, we want to block so that only one flushing is executed.
    // Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
    submitted: Mutex<bool>,
    finished: AtomicBool,
}

unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    #[inline]
    fn cleanup_finished(&mut self) {
        self.previous.cleanup_finished();
    }

    unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
        Ok(match self.previous.build_submission()? {
               SubmitAnyBuilder::Empty => {
                   let mut builder = SubmitCommandBufferBuilder::new();
                   builder.add_command_buffer(self.command_buffer.inner());
                   SubmitAnyBuilder::CommandBuffer(builder)
               },
               SubmitAnyBuilder::SemaphoresWait(sem) => {
                   let mut builder: SubmitCommandBufferBuilder = sem.into();
                   builder.add_command_buffer(self.command_buffer.inner());
                   SubmitAnyBuilder::CommandBuffer(builder)
               },
               SubmitAnyBuilder::CommandBuffer(mut builder) => {
                   // FIXME: add pipeline barrier
                   builder.add_command_buffer(self.command_buffer.inner());
                   SubmitAnyBuilder::CommandBuffer(builder)
               },
               SubmitAnyBuilder::QueuePresent(_) |
               SubmitAnyBuilder::BindSparse(_) => {
                   unimplemented!() // TODO:
                /*present.submit();     // TODO: wrong
                let mut builder = SubmitCommandBufferBuilder::new();
                builder.add_command_buffer(self.command_buffer.inner());
                SubmitAnyBuilder::CommandBuffer(builder)*/
               },
           })
    }

    #[inline]
    fn flush(&self) -> Result<(), FlushError> {
        unsafe {
            let mut submitted = self.submitted.lock().unwrap();
            if *submitted {
                return Ok(());
            }

            let queue = self.queue.clone();

            match self.build_submission()? {
                SubmitAnyBuilder::Empty => {},
                SubmitAnyBuilder::CommandBuffer(builder) => {
                    builder.submit(&queue)?;
                },
                _ => unreachable!(),
            };

            // Only write `true` here in order to try again next time if we failed to submit.
            *submitted = true;
            Ok(())
        }
    }

    #[inline]
    unsafe fn signal_finished(&self) {
        if self.finished.swap(true, Ordering::SeqCst) == false {
            self.command_buffer.unlock();
        }

        self.previous.signal_finished();
    }

    #[inline]
    fn queue_change_allowed(&self) -> bool {
        false
    }

    #[inline]
    fn queue(&self) -> Option<Arc<Queue>> {
        Some(self.queue.clone())
    }

    #[inline]
    fn check_buffer_access(
        &self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
        -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        match self.command_buffer
            .check_buffer_access(buffer, exclusive, queue) {
            Ok(v) => Ok(v),
            Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
            Err(AccessCheckError::Unknown) => {
                self.previous.check_buffer_access(buffer, exclusive, queue)
            },
        }
    }

    #[inline]
    fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool,
                          queue: &Queue)
                          -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
        match self.command_buffer
            .check_image_access(image, layout, exclusive, queue) {
            Ok(v) => Ok(v),
            Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
            Err(AccessCheckError::Unknown) => {
                self.previous
                    .check_image_access(image, layout, exclusive, queue)
            },
        }
    }
}

unsafe impl<F, Cb> DeviceOwned for CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.command_buffer.device()
    }
}

impl<F, Cb> Drop for CommandBufferExecFuture<F, Cb>
    where F: GpuFuture,
          Cb: CommandBuffer
{
    fn drop(&mut self) {
        unsafe {
            if !*self.finished.get_mut() {
                // TODO: handle errors?
                self.flush().unwrap();
                // Block until the queue finished.
                self.queue.wait().unwrap();
                self.command_buffer.unlock();
                self.previous.signal_finished();
            }
        }
    }
}

/// Error that can happen when attempting to execute a command buffer.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CommandBufferExecError {
    /// Access to a resource has been denied.
    AccessError(AccessError),

    /// The command buffer or one of the secondary command buffers it executes was created with the
    /// "one time submit" flag, but has already been submitted it the past.
    OneTimeSubmitAlreadySubmitted,

    /// The command buffer or one of the secondary command buffers it executes is already in use by
    /// the GPU and was not created with the "concurrent" flag.
    ExclusiveAlreadyInUse,

    // TODO: missing entries (eg. wrong queue family, secondary command buffer)
}

impl error::Error for CommandBufferExecError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CommandBufferExecError::AccessError(_) => {
                "access to a resource has been denied"
            },
            CommandBufferExecError::OneTimeSubmitAlreadySubmitted => {
                "the command buffer or one of the secondary command buffers it executes was \
                 created with the \"one time submit\" flag, but has already been submitted it \
                 the past"
            },
            CommandBufferExecError::ExclusiveAlreadyInUse => {
                "the command buffer or one of the secondary command buffers it executes is \
                 already in use by the GPU and was not created with the \"concurrent\" flag"
            },
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CommandBufferExecError::AccessError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for CommandBufferExecError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<AccessError> for CommandBufferExecError {
    #[inline]
    fn from(err: AccessError) -> CommandBufferExecError {
        CommandBufferExecError::AccessError(err)
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
use std::io::{Seek, SeekFrom, Read};
use std::path::{Path, PathBuf};

use error::{StoreError as SE, StoreErrorKind as SEK};
use error::ResultExt;

use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
use storeid::StoreId;
use file_abstraction::iter::PathIterator;

#[derive(Debug)]
pub enum FSFileAbstractionInstance {
    Absent(PathBuf),
    File(File, PathBuf)
}

impl FileAbstractionInstance for FSFileAbstractionInstance {

    /**
     * Get the content behind this file
     */
    fn get_file_content(&mut self, id: StoreId) -> Result<Entry, SE> {
        debug!("Getting lazy file: {:?}", self);
        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .chain_err(|| SEK::FileNotSeeked));

                let mut s = String::new();
                f.read_to_string(&mut s)
                    .chain_err(|| SEK::IoError)
                    .map(|_| s)
                    .and_then(|s| Entry::from_str(id, &s))
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(open_file(p).chain_err(|| SEK::FileNotFound)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            let mut s = String::new();
            f.read_to_string(&mut s)
                .chain_err(|| SEK::IoError)
                .map(|_| s)
                .and_then(|s| Entry::from_str(id, &s))
        } else {
            unreachable!()
        }
    }

    /**
     * Write the content of this file
     */
    fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
        use std::io::Write;

        let buf = buf.to_str().into_bytes();

        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .chain_err(|| SEK::FileNotCreated));

                try!(f.set_len(buf.len() as u64).chain_err(|| SEK::FileNotWritten));

                f.write_all(&buf).chain_err(|| SEK::FileNotWritten)
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(create_file(p).chain_err(|| SEK::FileNotCreated)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            return f.write_all(&buf).chain_err(|| SEK::FileNotWritten);
        }
        unreachable!();
    }
}

/// `FSFileAbstraction` state type
///
/// A lazy file is either absent, but a path to it is available, or it is present.
#[derive(Debug)]
pub struct FSFileAbstraction {
}

impl FSFileAbstraction {
    pub fn new() -> FSFileAbstraction {
        FSFileAbstraction { }
    }
}

impl FileAbstraction for FSFileAbstraction {

    fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
        remove_file(path).chain_err(|| SEK::FileNotRemoved)
    }

    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        copy(from, to).chain_err(|| SEK::FileNotCopied).map(|_| ())
    }

    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        rename(from, to).chain_err(|| SEK::FileNotRenamed)
    }

    fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
        debug!("Creating: {:?}", path);
        create_dir_all(path).chain_err(|| SEK::DirNotCreated)
    }

    fn exists(&self, path: &PathBuf) -> Result<bool, SE> {
        Ok(path.exists())
    }

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
        Box::new(FSFileAbstractionInstance::Absent(p))
    }

    /// We return nothing from the FS here.
    fn drain(&self) -> Result<Drain, SE> {
        Ok(Drain::empty())
    }

    /// FileAbstraction::fill implementation that consumes the Drain and writes everything to the
    /// filesystem
    fn fill(&mut self, mut d: Drain) -> Result<(), SE> {
        d.iter()
            .fold(Ok(()), |acc, (path, element)| {
                acc.and_then(|_| self.new_instance(path).write_file_content(&element))
            })
    }

    fn pathes_recursively(&self, basepath: PathBuf) -> Result<PathIterator, SE> {
        use walkdir::WalkDir;

        let i : Result<Vec<PathBuf>, SE> = WalkDir::new(basepath)
            .min_depth(1)
            .into_iter()
            .map(|r| {
                r.map(|e| PathBuf::from(e.path()))
                    .chain_err(|| SE::from_kind(SEK::FileError))
            })
            .fold(Ok(vec![]), |acc, e| {
                acc.and_then(move |mut a| {
                    a.push(try!(e));
                    Ok(a)
                })
            });
        Ok(PathIterator::new(Box::new(try!(i).into_iter())))
    }
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    if let Some(parent) = p.as_ref().parent() {
        debug!("Implicitely creating directory: {:?}", parent);
        if let Err(e) = create_dir_all(parent) {
            return Err(e);
        }
    }
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

<commit_msg>Fix: Create directory before renaming file<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename};
use std::io::{Seek, SeekFrom, Read};
use std::path::{Path, PathBuf};

use error::{StoreError as SE, StoreErrorKind as SEK};
use error::ResultExt;

use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
use storeid::StoreId;
use file_abstraction::iter::PathIterator;

#[derive(Debug)]
pub enum FSFileAbstractionInstance {
    Absent(PathBuf),
    File(File, PathBuf)
}

impl FileAbstractionInstance for FSFileAbstractionInstance {

    /**
     * Get the content behind this file
     */
    fn get_file_content(&mut self, id: StoreId) -> Result<Entry, SE> {
        debug!("Getting lazy file: {:?}", self);
        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .chain_err(|| SEK::FileNotSeeked));

                let mut s = String::new();
                f.read_to_string(&mut s)
                    .chain_err(|| SEK::IoError)
                    .map(|_| s)
                    .and_then(|s| Entry::from_str(id, &s))
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(open_file(p).chain_err(|| SEK::FileNotFound)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            let mut s = String::new();
            f.read_to_string(&mut s)
                .chain_err(|| SEK::IoError)
                .map(|_| s)
                .and_then(|s| Entry::from_str(id, &s))
        } else {
            unreachable!()
        }
    }

    /**
     * Write the content of this file
     */
    fn write_file_content(&mut self, buf: &Entry) -> Result<(), SE> {
        use std::io::Write;

        let buf = buf.to_str().into_bytes();

        let (file, path) = match *self {
            FSFileAbstractionInstance::File(ref mut f, _) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                try!(f.seek(SeekFrom::Start(0))
                    .chain_err(|| SEK::FileNotCreated));

                try!(f.set_len(buf.len() as u64).chain_err(|| SEK::FileNotWritten));

                f.write_all(&buf).chain_err(|| SEK::FileNotWritten)
            },
            FSFileAbstractionInstance::Absent(ref p) =>
                (try!(create_file(p).chain_err(|| SEK::FileNotCreated)), p.clone()),
        };
        *self = FSFileAbstractionInstance::File(file, path);
        if let FSFileAbstractionInstance::File(ref mut f, _) = *self {
            return f.write_all(&buf).chain_err(|| SEK::FileNotWritten);
        }
        unreachable!();
    }
}

/// `FSFileAbstraction` state type
///
/// A lazy file is either absent, but a path to it is available, or it is present.
#[derive(Debug)]
pub struct FSFileAbstraction {
}

impl FSFileAbstraction {
    pub fn new() -> FSFileAbstraction {
        FSFileAbstraction { }
    }
}

impl FileAbstraction for FSFileAbstraction {

    fn remove_file(&self, path: &PathBuf) -> Result<(), SE> {
        remove_file(path).chain_err(|| SEK::FileNotRemoved)
    }

    fn copy(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        copy(from, to).chain_err(|| SEK::FileNotCopied).map(|_| ())
    }

    fn rename(&self, from: &PathBuf, to: &PathBuf) -> Result<(), SE> {
        match to.parent() {
            Some(p) => if !p.exists() {
                debug!("Creating: {:?}", p);
                let _ = try!(create_dir_all(&PathBuf::from(p)));
            },
            None => {
                debug!("Failed to find parent. This looks like it will fail now");
                //nothing
            },
        }

        debug!("Renaming {:?} to {:?}", from, to);
        rename(from, to).chain_err(|| SEK::FileNotRenamed)
    }

    fn create_dir_all(&self, path: &PathBuf) -> Result<(), SE> {
        debug!("Creating: {:?}", path);
        create_dir_all(path).chain_err(|| SEK::DirNotCreated)
    }

    fn exists(&self, path: &PathBuf) -> Result<bool, SE> {
        Ok(path.exists())
    }

    fn new_instance(&self, p: PathBuf) -> Box<FileAbstractionInstance> {
        Box::new(FSFileAbstractionInstance::Absent(p))
    }

    /// We return nothing from the FS here.
    fn drain(&self) -> Result<Drain, SE> {
        Ok(Drain::empty())
    }

    /// FileAbstraction::fill implementation that consumes the Drain and writes everything to the
    /// filesystem
    fn fill(&mut self, mut d: Drain) -> Result<(), SE> {
        d.iter()
            .fold(Ok(()), |acc, (path, element)| {
                acc.and_then(|_| self.new_instance(path).write_file_content(&element))
            })
    }

    fn pathes_recursively(&self, basepath: PathBuf) -> Result<PathIterator, SE> {
        use walkdir::WalkDir;

        let i : Result<Vec<PathBuf>, SE> = WalkDir::new(basepath)
            .min_depth(1)
            .into_iter()
            .map(|r| {
                r.map(|e| PathBuf::from(e.path()))
                    .chain_err(|| SE::from_kind(SEK::FileError))
            })
            .fold(Ok(vec![]), |acc, e| {
                acc.and_then(move |mut a| {
                    a.push(try!(e));
                    Ok(a)
                })
            });
        Ok(PathIterator::new(Box::new(try!(i).into_iter())))
    }
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    if let Some(parent) = p.as_ref().parent() {
        debug!("Implicitely creating directory: {:?}", parent);
        if let Err(e) = create_dir_all(parent) {
            return Err(e);
        }
    }
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

<|endoftext|>


<commit_before>#![cfg(feature = "use_std")]

extern crate futures;

use futures::{Future, Stream, Sink, Async, AsyncSink};
use futures::future::lazy;
use futures::sync::mpsc;

use std::time::Duration;
use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};

trait AssertSend: Send {}
impl AssertSend for mpsc::Sender<i32> {}
impl AssertSend for mpsc::Receiver<i32> {}

#[test]
fn send_recv() {
    let (tx, rx) = mpsc::channel::<i32>(16);
    let mut rx = rx.wait();

    tx.send(1).wait().unwrap();

    assert_eq!(rx.next().unwrap(), Ok(1));
}

#[test]
fn send_recv_no_buffer() {
    let (mut tx, mut rx) = mpsc::channel::<i32>(0);

    // Run on a task context
    lazy(move || {
        assert!(tx.poll_complete().unwrap().is_ready());

        // Send first message

        let res = tx.start_send(1).unwrap();
        assert!(is_ready(&res));

        // Send second message
        let res = tx.start_send(2).unwrap();
        assert!(!is_ready(&res));

        // Take the value
        assert_eq!(rx.poll().unwrap(), Async::Ready(Some(1)));

        let res = tx.start_send(2).unwrap();
        assert!(is_ready(&res));

        // Take the value
        assert_eq!(rx.poll().unwrap(), Async::Ready(Some(2)));

        Ok::<(), ()>(())
    }).wait().unwrap();
}

#[test]
fn send_shared_recv() {
    let (tx1, rx) = mpsc::channel::<i32>(16);
    let tx2 = tx1.clone();
    let mut rx = rx.wait();

    tx1.send(1).wait().unwrap();
    assert_eq!(rx.next().unwrap(), Ok(1));

    tx2.send(2).wait().unwrap();
    assert_eq!(rx.next().unwrap(), Ok(2));
}

#[test]
fn send_recv_threads() {
    let (tx, rx) = mpsc::channel::<i32>(16);
    let mut rx = rx.wait();

    thread::spawn(move|| {
        tx.send(1).wait().unwrap();
    });

    assert_eq!(rx.next().unwrap(), Ok(1));
}

#[test]
fn send_recv_threads_no_capacity() {
    let (mut tx, rx) = mpsc::channel::<i32>(0);
    let mut rx = rx.wait();

    let t = thread::spawn(move|| {
        tx = tx.send(1).wait().unwrap();
        tx = tx.send(2).wait().unwrap();
    });

    thread::sleep(Duration::from_millis(100));
    assert_eq!(rx.next().unwrap(), Ok(1));

    thread::sleep(Duration::from_millis(100));
    assert_eq!(rx.next().unwrap(), Ok(2));

    t.join().unwrap();
}

#[test]
fn recv_close_gets_none() {
    let (tx, mut rx) = mpsc::channel::<i32>(10);

    // Run on a task context
    lazy(move || {
        rx.close();

        assert_eq!(rx.poll(), Ok(Async::Ready(None)));

        drop(tx);

        Ok::<(), ()>(())
    }).wait().unwrap();
}

#[test]
fn tx_close_gets_none() {
    let (_, mut rx) = mpsc::channel::<i32>(10);

    // Run on a task context
    lazy(move || {
        assert_eq!(rx.poll(), Ok(Async::Ready(None)));
        assert_eq!(rx.poll(), Ok(Async::Ready(None)));

        Ok::<(), ()>(())
    }).wait().unwrap();
}

#[test]
fn stress_shared_unbounded() {
    const AMT: u32 = 10000;
    const NTHREADS: u32 = 8;
    let (tx, rx) = mpsc::unbounded::<i32>();
    let mut rx = rx.wait();

    let t = thread::spawn(move|| {
        for _ in 0..AMT * NTHREADS {
            assert_eq!(rx.next().unwrap(), Ok(1));
        }

        if rx.next().is_some() {
            panic!();
        }
    });

    for _ in 0..NTHREADS {
        let tx = tx.clone();

        thread::spawn(move|| {
            for _ in 0..AMT {
                mpsc::UnboundedSender::send(&tx, 1).unwrap();
            }
        });
    }

    drop(tx);

    t.join().ok().unwrap();
}

#[test]
fn stress_shared_bounded_hard() {
    const AMT: u32 = 10000;
    const NTHREADS: u32 = 8;
    let (tx, rx) = mpsc::channel::<i32>(0);
    let mut rx = rx.wait();

    let t = thread::spawn(move|| {
        for _ in 0..AMT * NTHREADS {
            assert_eq!(rx.next().unwrap(), Ok(1));
        }

        if rx.next().is_some() {
            panic!();
        }
    });

    for _ in 0..NTHREADS {
        let mut tx = tx.clone();

        thread::spawn(move|| {
            for _ in 0..AMT {
                tx = tx.send(1).wait().unwrap();
            }
        });
    }

    drop(tx);

    t.join().ok().unwrap();
}

#[test]
fn stress_receiver_multi_task_bounded_hard() {
    const AMT: usize = 10_000;
    const NTHREADS: u32 = 2;

    let (mut tx, rx) = mpsc::channel::<usize>(0);
    let rx = Arc::new(Mutex::new(Some(rx)));
    let n = Arc::new(AtomicUsize::new(0));

    let mut th = vec![];

    for _ in 0..NTHREADS {
        let rx = rx.clone();
        let n = n.clone();

        let t = thread::spawn(move || {
            let mut i = 0;

            loop {
                i += 1;
                let mut lock = rx.lock().ok().unwrap();

                match lock.take() {
                    Some(mut rx) => {
                        if i % 5 == 0 {
                            let (item, rest) = rx.into_future().wait().ok().unwrap();

                            if item.is_none() {
                                break;
                            }

                            n.fetch_add(1, Ordering::Relaxed);
                            *lock = Some(rest);
                        } else {
                            // Just poll
                            let n = n.clone();
                            let r = lazy(move || {
                                let r = match rx.poll().unwrap() {
                                    Async::Ready(Some(_)) => {
                                        n.fetch_add(1, Ordering::Relaxed);
                                        *lock = Some(rx);
                                        false
                                    }
                                    Async::Ready(None) => {
                                        true
                                    }
                                    Async::NotReady => {
                                        *lock = Some(rx);
                                        false
                                    }
                                };

                                Ok::<bool, ()>(r)
                            }).wait().unwrap();

                            if r {
                                break;
                            }
                        }
                    }
                    None => break,
                }
            }
        });

        th.push(t);
    }

    for i in 0..AMT {
        tx = tx.send(i).wait().unwrap();
    }

    drop(tx);

    for t in th {
        t.join().unwrap();
    }

    assert_eq!(AMT, n.load(Ordering::Relaxed));
}

fn is_ready<T>(res: &AsyncSink<T>) -> bool {
    match *res {
        AsyncSink::Ready => true,
        _ => false,
    }
}
<commit_msg>Two more stress tests for sync::mpsc<commit_after>#![cfg(feature = "use_std")]

extern crate futures;

use futures::{Future, Stream, Sink, Async, AsyncSink};
use futures::future::lazy;
use futures::sync::mpsc;

use std::time::Duration;
use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};

mod support;
use support::*;

trait AssertSend: Send {}
impl AssertSend for mpsc::Sender<i32> {}
impl AssertSend for mpsc::Receiver<i32> {}

#[test]
fn send_recv() {
    let (tx, rx) = mpsc::channel::<i32>(16);
    let mut rx = rx.wait();

    tx.send(1).wait().unwrap();

    assert_eq!(rx.next().unwrap(), Ok(1));
}

#[test]
fn send_recv_no_buffer() {
    let (mut tx, mut rx) = mpsc::channel::<i32>(0);

    // Run on a task context
    lazy(move || {
        assert!(tx.poll_complete().unwrap().is_ready());

        // Send first message

        let res = tx.start_send(1).unwrap();
        assert!(is_ready(&res));

        // Send second message
        let res = tx.start_send(2).unwrap();
        assert!(!is_ready(&res));

        // Take the value
        assert_eq!(rx.poll().unwrap(), Async::Ready(Some(1)));

        let res = tx.start_send(2).unwrap();
        assert!(is_ready(&res));

        // Take the value
        assert_eq!(rx.poll().unwrap(), Async::Ready(Some(2)));

        Ok::<(), ()>(())
    }).wait().unwrap();
}

#[test]
fn send_shared_recv() {
    let (tx1, rx) = mpsc::channel::<i32>(16);
    let tx2 = tx1.clone();
    let mut rx = rx.wait();

    tx1.send(1).wait().unwrap();
    assert_eq!(rx.next().unwrap(), Ok(1));

    tx2.send(2).wait().unwrap();
    assert_eq!(rx.next().unwrap(), Ok(2));
}

#[test]
fn send_recv_threads() {
    let (tx, rx) = mpsc::channel::<i32>(16);
    let mut rx = rx.wait();

    thread::spawn(move|| {
        tx.send(1).wait().unwrap();
    });

    assert_eq!(rx.next().unwrap(), Ok(1));
}

#[test]
fn send_recv_threads_no_capacity() {
    let (mut tx, rx) = mpsc::channel::<i32>(0);
    let mut rx = rx.wait();

    let t = thread::spawn(move|| {
        tx = tx.send(1).wait().unwrap();
        tx = tx.send(2).wait().unwrap();
    });

    thread::sleep(Duration::from_millis(100));
    assert_eq!(rx.next().unwrap(), Ok(1));

    thread::sleep(Duration::from_millis(100));
    assert_eq!(rx.next().unwrap(), Ok(2));

    t.join().unwrap();
}

#[test]
fn recv_close_gets_none() {
    let (tx, mut rx) = mpsc::channel::<i32>(10);

    // Run on a task context
    lazy(move || {
        rx.close();

        assert_eq!(rx.poll(), Ok(Async::Ready(None)));

        drop(tx);

        Ok::<(), ()>(())
    }).wait().unwrap();
}

#[test]
fn tx_close_gets_none() {
    let (_, mut rx) = mpsc::channel::<i32>(10);

    // Run on a task context
    lazy(move || {
        assert_eq!(rx.poll(), Ok(Async::Ready(None)));
        assert_eq!(rx.poll(), Ok(Async::Ready(None)));

        Ok::<(), ()>(())
    }).wait().unwrap();
}

#[test]
fn stress_shared_unbounded() {
    const AMT: u32 = 10000;
    const NTHREADS: u32 = 8;
    let (tx, rx) = mpsc::unbounded::<i32>();
    let mut rx = rx.wait();

    let t = thread::spawn(move|| {
        for _ in 0..AMT * NTHREADS {
            assert_eq!(rx.next().unwrap(), Ok(1));
        }

        if rx.next().is_some() {
            panic!();
        }
    });

    for _ in 0..NTHREADS {
        let tx = tx.clone();

        thread::spawn(move|| {
            for _ in 0..AMT {
                mpsc::UnboundedSender::send(&tx, 1).unwrap();
            }
        });
    }

    drop(tx);

    t.join().ok().unwrap();
}

#[test]
fn stress_shared_bounded_hard() {
    const AMT: u32 = 10000;
    const NTHREADS: u32 = 8;
    let (tx, rx) = mpsc::channel::<i32>(0);
    let mut rx = rx.wait();

    let t = thread::spawn(move|| {
        for _ in 0..AMT * NTHREADS {
            assert_eq!(rx.next().unwrap(), Ok(1));
        }

        if rx.next().is_some() {
            panic!();
        }
    });

    for _ in 0..NTHREADS {
        let mut tx = tx.clone();

        thread::spawn(move|| {
            for _ in 0..AMT {
                tx = tx.send(1).wait().unwrap();
            }
        });
    }

    drop(tx);

    t.join().ok().unwrap();
}

#[test]
fn stress_receiver_multi_task_bounded_hard() {
    const AMT: usize = 10_000;
    const NTHREADS: u32 = 2;

    let (mut tx, rx) = mpsc::channel::<usize>(0);
    let rx = Arc::new(Mutex::new(Some(rx)));
    let n = Arc::new(AtomicUsize::new(0));

    let mut th = vec![];

    for _ in 0..NTHREADS {
        let rx = rx.clone();
        let n = n.clone();

        let t = thread::spawn(move || {
            let mut i = 0;

            loop {
                i += 1;
                let mut lock = rx.lock().ok().unwrap();

                match lock.take() {
                    Some(mut rx) => {
                        if i % 5 == 0 {
                            let (item, rest) = rx.into_future().wait().ok().unwrap();

                            if item.is_none() {
                                break;
                            }

                            n.fetch_add(1, Ordering::Relaxed);
                            *lock = Some(rest);
                        } else {
                            // Just poll
                            let n = n.clone();
                            let r = lazy(move || {
                                let r = match rx.poll().unwrap() {
                                    Async::Ready(Some(_)) => {
                                        n.fetch_add(1, Ordering::Relaxed);
                                        *lock = Some(rx);
                                        false
                                    }
                                    Async::Ready(None) => {
                                        true
                                    }
                                    Async::NotReady => {
                                        *lock = Some(rx);
                                        false
                                    }
                                };

                                Ok::<bool, ()>(r)
                            }).wait().unwrap();

                            if r {
                                break;
                            }
                        }
                    }
                    None => break,
                }
            }
        });

        th.push(t);
    }

    for i in 0..AMT {
        tx = tx.send(i).wait().unwrap();
    }

    drop(tx);

    for t in th {
        t.join().unwrap();
    }

    assert_eq!(AMT, n.load(Ordering::Relaxed));
}

/// Stress test that receiver properly receives all the messages
/// after sender dropped.
#[test]
fn stress_drop_sender() {
    fn list() -> Box<Stream<Item=i32, Error=u32>> {
        let (tx, rx) = mpsc::channel(1);
        tx.send(Ok(1))
          .and_then(|tx| tx.send(Ok(2)))
          .and_then(|tx| tx.send(Ok(3)))
          .forget();
        rx.then(|r| r.unwrap()).boxed()
    }

    for _ in 0..10000 {
        assert_eq!(list().wait().collect::<Result<Vec<_>, _>>(),
        Ok(vec![1, 2, 3]));
    }
}

/// Stress test that after receiver dropped,
/// no messages are lost.
fn stress_close_receiver_iter() {
    let (tx, rx) = mpsc::unbounded();
    let (unwritten_tx, unwritten_rx) = std::sync::mpsc::channel();
    thread::spawn(move || {
        for i in 1.. {
            if let Err(_) = mpsc::UnboundedSender::send(&tx, i) {
                unwritten_tx.send(i).expect("unwritten_tx");
                return;
            }
        }
    });

    let mut rx = rx.wait();

    // Read one message to make sure thread effectively started
    assert_eq!(Some(Ok(1)), rx.next());

    rx.get_mut().close();

    for i in 2.. {
        match rx.next() {
            Some(Ok(r)) => assert!(i == r),
            Some(Err(_)) => unreachable!(),
            None => {
                let unwritten = unwritten_rx.recv().expect("unwritten_rx");
                assert_eq!(unwritten, i);
                return;
            }
        }
    }
}

#[test]
fn stress_close_receiver() {
    for _ in 0..10000 {
        stress_close_receiver_iter();
    }
}

fn is_ready<T>(res: &AsyncSink<T>) -> bool {
    match *res {
        AsyncSink::Ready => true,
        _ => false,
    }
}
<|endoftext|>