<commit_before>use std::mem;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};

use time::Timespec;
use byteorder::{ByteOrder, LittleEndian};

use super::super::crypto::{Hash, PublicKey};

use super::Error;

pub trait Field<'a> {
    // TODO: use Read and Cursor
    // TODO: debug_assert_eq!(to-from == size of Self)
    fn read(buffer: &'a [u8], from: usize, to: usize) -> Self;
    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize);

    #[allow(unused_variables)]
    fn check(buffer: &'a [u8], from: usize, to: usize) -> Result<(), Error> {
        Ok(())
    }
}

impl<'a> Field<'a> for bool {
    fn read(buffer: &'a [u8], from: usize, _: usize) -> bool {
        buffer[from] == 1
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, _: usize) {
        buffer[from] = if *self { 1 } else { 0 }
    }

    fn check(buffer: &'a [u8], from: usize, _: usize) -> Result<(), Error> {
        if buffer[from] != 0 && buffer[from] != 1 {
            Err(Error::IncorrectBoolean {
                position: from as u32,
                value: buffer[from],
            })
        } else {
            Ok(())
        }
    }
}

impl<'a> Field<'a> for u32 {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> u32 {
        LittleEndian::read_u32(&buffer[from..to])
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        LittleEndian::write_u32(&mut buffer[from..to], *self)
    }
}

impl<'a> Field<'a> for u64 {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> u64 {
        LittleEndian::read_u64(&buffer[from..to])
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        LittleEndian::write_u64(&mut buffer[from..to], *self)
    }
}

impl<'a> Field<'a> for &'a Hash {
    fn read(buffer: &'a [u8], from: usize, _: usize) -> &'a Hash {
        unsafe { mem::transmute(&buffer[from]) }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        buffer[from..to].copy_from_slice(self.as_ref());
    }
}

impl<'a> Field<'a> for &'a PublicKey {
    fn read(buffer: &'a [u8], from: usize, _: usize) -> &'a PublicKey {
        unsafe { mem::transmute(&buffer[from]) }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        buffer[from..to].copy_from_slice(self.as_ref());
    }
}

impl<'a> Field<'a> for Timespec {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> Timespec {
        let nsec = LittleEndian::read_u64(&buffer[from..to]);
        Timespec {
            sec: (nsec / 1_000_000_000) as i64,
            nsec: (nsec % 1_000_000_000) as i32,
        }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        let nsec = (self.sec as u64) * 1_000_000_000 + self.nsec as u64;
        LittleEndian::write_u64(&mut buffer[from..to], nsec)
    }
}

impl<'a> Field<'a> for SocketAddr {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> SocketAddr {
        let ip = Ipv4Addr::new(buffer[from + 0],
                               buffer[from + 1],
                               buffer[from + 2],
                               buffer[from + 3]);
        let port = LittleEndian::read_u16(&buffer[from + 4..to]);
        SocketAddr::V4(SocketAddrV4::new(ip, port))
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        match *self {
            SocketAddr::V4(addr) => {
                buffer[from..to - 2].copy_from_slice(&addr.ip().octets());
            }
            SocketAddr::V6(_) => {
                // FIXME: Supporting Ipv6
                panic!("Ipv6 are currently unsupported")
            }
        }
        LittleEndian::write_u16(&mut buffer[to - 2..to], self.port());
    }
}

pub trait SegmentField<'a> {
    const ITEM_SIZE: usize;

    fn from_slice(slice: &'a [u8]) -> Self;
    fn as_slice(&self) -> &'a [u8];
    fn count(&self) -> u32;

    #[allow(unused_variables)]
    fn check_data(slice: &'a [u8], pos: u32) -> Result<(), Error> {
        Ok(())
    }
}

impl<'a, T> Field<'a> for T
    where T: SegmentField<'a>
{
    fn read(buffer: &'a [u8], from: usize, to: usize) -> T {
        unsafe {
            let pos = LittleEndian::read_u32(&buffer[from..from + 4]);
            let count = LittleEndian::read_u32(&buffer[from + 4..to]);
            let ptr = buffer.as_ptr().offset(pos as isize);
            let len = (count as usize) * Self::ITEM_SIZE;
            Self::from_slice(::std::slice::from_raw_parts(ptr as *const u8, len))
        }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        let pos = buffer.len();
        LittleEndian::write_u32(&mut buffer[from..from + 4], pos as u32);
        LittleEndian::write_u32(&mut buffer[from + 4..to], self.count());
        buffer.extend_from_slice(self.as_slice());
    }

    fn check(buffer: &'a [u8], from: usize, to: usize) -> Result<(), Error> {
        let pos = LittleEndian::read_u32(&buffer[from..from + 4]);
        let count = LittleEndian::read_u32(&buffer[from + 4..to]);

        if count == 0 {
            return Ok(());
        }

        let start = pos as usize;

        if start < from + 8 {
            return Err(Error::IncorrectSegmentRefference {
                position: from as u32,
                value: pos,
            });
        }

        let end = start + Self::ITEM_SIZE * (count as usize);

        if end > buffer.len() {
            return Err(Error::IncorrectSegmentSize {
                position: (from + 4) as u32,
                value: count,
            });
        }

        Self::check_data(unsafe { ::std::slice::from_raw_parts(pos as *const u8, count as usize) },
                         from as u32)
    }
}

impl<'a> SegmentField<'a> for &'a [u8] {
    const ITEM_SIZE: usize = 1;

    fn from_slice(slice: &'a [u8]) -> Self {
        slice
    }

    fn as_slice(&self) -> &'a [u8] {
        self
    }

    fn count(&self) -> u32 {
        self.len() as u32
    }
}

impl<'a> SegmentField<'a> for &'a [Hash] {
    const ITEM_SIZE: usize = 32;

    fn from_slice(slice: &'a [u8]) -> Self {
        unsafe { ::std::slice::from_raw_parts(slice.as_ptr() as *const Hash, slice.len() / 32) }
    }

    fn as_slice(&self) -> &'a [u8] {
        unsafe { ::std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * 32) }
    }

    fn count(&self) -> u32 {
        self.len() as u32
    }
}

impl<'a> SegmentField<'a> for &'a str {
    const ITEM_SIZE: usize = 32;

    fn from_slice(slice: &'a [u8]) -> Self {
        unsafe { ::std::str::from_utf8_unchecked(slice) }
    }

    fn as_slice(&self) -> &'a [u8] {
        self.as_bytes()
    }

    fn count(&self) -> u32 {
        self.len() as u32
    }

    fn check_data(slice: &'a [u8], pos: u32) -> Result<(), Error> {
        if let Err(e) = ::std::str::from_utf8(slice) {
            return Err(Error::Utf8 {
                position: pos,
                error: e,
            });
        }
        Ok(())
    }
}
<commit_msg>Use octets for Ipv4Addr<commit_after>use std::mem;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};

use time::Timespec;
use byteorder::{ByteOrder, LittleEndian};

use super::super::crypto::{Hash, PublicKey};

use super::Error;

pub trait Field<'a> {
    // TODO: use Read and Cursor
    // TODO: debug_assert_eq!(to-from == size of Self)
    fn read(buffer: &'a [u8], from: usize, to: usize) -> Self;
    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize);

    #[allow(unused_variables)]
    fn check(buffer: &'a [u8], from: usize, to: usize) -> Result<(), Error> {
        Ok(())
    }
}

impl<'a> Field<'a> for bool {
    fn read(buffer: &'a [u8], from: usize, _: usize) -> bool {
        buffer[from] == 1
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, _: usize) {
        buffer[from] = if *self { 1 } else { 0 }
    }

    fn check(buffer: &'a [u8], from: usize, _: usize) -> Result<(), Error> {
        if buffer[from] != 0 && buffer[from] != 1 {
            Err(Error::IncorrectBoolean {
                position: from as u32,
                value: buffer[from],
            })
        } else {
            Ok(())
        }
    }
}

impl<'a> Field<'a> for u32 {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> u32 {
        LittleEndian::read_u32(&buffer[from..to])
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        LittleEndian::write_u32(&mut buffer[from..to], *self)
    }
}

impl<'a> Field<'a> for u64 {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> u64 {
        LittleEndian::read_u64(&buffer[from..to])
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        LittleEndian::write_u64(&mut buffer[from..to], *self)
    }
}

impl<'a> Field<'a> for &'a Hash {
    fn read(buffer: &'a [u8], from: usize, _: usize) -> &'a Hash {
        unsafe { mem::transmute(&buffer[from]) }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        buffer[from..to].copy_from_slice(self.as_ref());
    }
}

impl<'a> Field<'a> for &'a PublicKey {
    fn read(buffer: &'a [u8], from: usize, _: usize) -> &'a PublicKey {
        unsafe { mem::transmute(&buffer[from]) }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        buffer[from..to].copy_from_slice(self.as_ref());
    }
}

impl<'a> Field<'a> for Timespec {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> Timespec {
        let nsec = LittleEndian::read_u64(&buffer[from..to]);
        Timespec {
            sec: (nsec / 1_000_000_000) as i64,
            nsec: (nsec % 1_000_000_000) as i32,
        }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        let nsec = (self.sec as u64) * 1_000_000_000 + self.nsec as u64;
        LittleEndian::write_u64(&mut buffer[from..to], nsec)
    }
}

impl<'a> Field<'a> for SocketAddr {
    fn read(buffer: &'a [u8], from: usize, to: usize) -> SocketAddr {
        let mut octets = [0u8; 4];
        octets.copy_from_slice(&buffer[from..from+4]);
        let ip = Ipv4Addr::from(octets);
        let port = LittleEndian::read_u16(&buffer[from + 4..to]);
        SocketAddr::V4(SocketAddrV4::new(ip, port))
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        match *self {
            SocketAddr::V4(addr) => {
                buffer[from..to - 2].copy_from_slice(&addr.ip().octets());
            }
            SocketAddr::V6(_) => {
                // FIXME: Supporting Ipv6
                panic!("Ipv6 are currently unsupported")
            }
        }
        LittleEndian::write_u16(&mut buffer[to - 2..to], self.port());
    }
}

pub trait SegmentField<'a> {
    const ITEM_SIZE: usize;

    fn from_slice(slice: &'a [u8]) -> Self;
    fn as_slice(&self) -> &'a [u8];
    fn count(&self) -> u32;

    #[allow(unused_variables)]
    fn check_data(slice: &'a [u8], pos: u32) -> Result<(), Error> {
        Ok(())
    }
}

impl<'a, T> Field<'a> for T
    where T: SegmentField<'a>
{
    fn read(buffer: &'a [u8], from: usize, to: usize) -> T {
        unsafe {
            let pos = LittleEndian::read_u32(&buffer[from..from + 4]);
            let count = LittleEndian::read_u32(&buffer[from + 4..to]);
            let ptr = buffer.as_ptr().offset(pos as isize);
            let len = (count as usize) * Self::ITEM_SIZE;
            Self::from_slice(::std::slice::from_raw_parts(ptr as *const u8, len))
        }
    }

    fn write(&self, buffer: &'a mut Vec<u8>, from: usize, to: usize) {
        let pos = buffer.len();
        LittleEndian::write_u32(&mut buffer[from..from + 4], pos as u32);
        LittleEndian::write_u32(&mut buffer[from + 4..to], self.count());
        buffer.extend_from_slice(self.as_slice());
    }

    fn check(buffer: &'a [u8], from: usize, to: usize) -> Result<(), Error> {
        let pos = LittleEndian::read_u32(&buffer[from..from + 4]);
        let count = LittleEndian::read_u32(&buffer[from + 4..to]);

        if count == 0 {
            return Ok(());
        }

        let start = pos as usize;

        if start < from + 8 {
            return Err(Error::IncorrectSegmentRefference {
                position: from as u32,
                value: pos,
            });
        }

        let end = start + Self::ITEM_SIZE * (count as usize);

        if end > buffer.len() {
            return Err(Error::IncorrectSegmentSize {
                position: (from + 4) as u32,
                value: count,
            });
        }

        Self::check_data(unsafe { ::std::slice::from_raw_parts(pos as *const u8, count as usize) },
                         from as u32)
    }
}

impl<'a> SegmentField<'a> for &'a [u8] {
    const ITEM_SIZE: usize = 1;

    fn from_slice(slice: &'a [u8]) -> Self {
        slice
    }

    fn as_slice(&self) -> &'a [u8] {
        self
    }

    fn count(&self) -> u32 {
        self.len() as u32
    }
}

impl<'a> SegmentField<'a> for &'a [Hash] {
    const ITEM_SIZE: usize = 32;

    fn from_slice(slice: &'a [u8]) -> Self {
        unsafe { ::std::slice::from_raw_parts(slice.as_ptr() as *const Hash, slice.len() / 32) }
    }

    fn as_slice(&self) -> &'a [u8] {
        unsafe { ::std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * 32) }
    }

    fn count(&self) -> u32 {
        self.len() as u32
    }
}

impl<'a> SegmentField<'a> for &'a str {
    const ITEM_SIZE: usize = 32;

    fn from_slice(slice: &'a [u8]) -> Self {
        unsafe { ::std::str::from_utf8_unchecked(slice) }
    }

    fn as_slice(&self) -> &'a [u8] {
        self.as_bytes()
    }

    fn count(&self) -> u32 {
        self.len() as u32
    }

    fn check_data(slice: &'a [u8], pos: u32) -> Result<(), Error> {
        if let Err(e) = ::std::str::from_utf8(slice) {
            return Err(Error::Utf8 {
                position: pos,
                error: e,
            });
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! IO
//!
//! This module contains a number of functions for working with
//! `AsyncRead` and `AsyncWrite` types, including the
//! `AsyncReadExt` and `AsyncWriteExt` traits which add methods
//! to the `AsyncRead` and `AsyncWrite` types.

use std::vec::Vec;

pub use futures_io::{AsyncRead, AsyncWrite, IoVec};

// Temporarily removed until AsyncBufRead is implemented
// pub use io::lines::{lines, Lines};
// pub use io::read_until::{read_until, ReadUntil};
// mod lines;
// mod read_until;

mod allow_std;
pub use self::allow_std::AllowStdIo;

mod copy_into;
pub use self::copy_into::CopyInto;

mod flush;
pub use self::flush::Flush;

mod read;
pub use self::read::Read;

mod read_exact;
pub use self::read_exact::ReadExact;

mod read_to_end;
pub use self::read_to_end::ReadToEnd;

mod close;
pub use self::close::Close;

mod split;
pub use self::split::{ReadHalf, WriteHalf};

mod window;
pub use self::window::Window;

mod write_all;
pub use self::write_all::WriteAll;

/// An extension trait which adds utility methods to `AsyncRead` types.
pub trait AsyncReadExt: AsyncRead {
    /// Creates a future which copies all the bytes from one object to another.
    ///
    /// The returned future will copy all the bytes read from this `AsyncRead` into the
    /// `writer` specified. This future will only complete once the `reader` has hit
    /// EOF and all bytes have been written to and flushed from the `writer`
    /// provided.
    ///
    /// On success the number of bytes is returned.
    fn copy_into<'a, W>(
        &'a mut self,
        writer: &'a mut W,
    ) -> CopyInto<'a, Self, W>
        where W: AsyncWrite,
    {
        CopyInto::new(self, writer)
    }

    /// Tries to read some bytes directly into the given `buf` in asynchronous
    /// manner, returning a future type.
    ///
    /// The returned future will resolve to the number of bytes read once the read
    /// operation is completed.
    fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> {
        Read::new(self, buf)
    }

    /// Creates a future which will read exactly enough bytes to fill `buf`,
    /// returning an error if EOF is hit sooner.
    ///
    /// The returned future will resolve once the read operation is completed.
    ///
    /// In the case of an error the buffer and the object will be discarded, with
    /// the error yielded.
    fn read_exact<'a>(
        &'a mut self,
        buf: &'a mut [u8],
    ) -> ReadExact<'a, Self> {
        ReadExact::new(self, buf)
    }

    /// Creates a future which will read all the bytes from this `AsyncRead`.
    fn read_to_end<'a>(
        &'a mut self,
        buf: &'a mut Vec<u8>,
    ) -> ReadToEnd<'a, Self> {
        ReadToEnd::new(self, buf)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `Read` and `Write` traits,
    /// respectively.
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }
}

impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}

/// An extension trait which adds utility methods to `AsyncWrite` types.
pub trait AsyncWriteExt: AsyncWrite {
    /// Creates a future which will entirely flush this `AsyncWrite`.
    fn flush<'a>(&'a mut self) -> Flush<'a, Self> {
        Flush::new(self)
    }

    /// Creates a future which will entirely close this `AsyncWrite`.
    fn close<'a>(&'a mut self) -> Close<'a, Self> {
        Close::new(self)
    }

    /// Write data into this object.
    ///
    /// Creates a future that will write the entire contents of the buffer `buf` into
    /// this `AsyncWrite`.
    ///
    /// The returned future will not complete until all the data has been written.
    fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> {
        WriteAll::new(self, buf)
    }
}

impl<W: AsyncWrite + ?Sized> AsyncWriteExt for W {}
<commit_msg>Add examples to AsyncReadExt and AsyncWriteExt methods<commit_after>//! IO
//!
//! This module contains a number of functions for working with
//! `AsyncRead` and `AsyncWrite` types, including the
//! `AsyncReadExt` and `AsyncWriteExt` traits which add methods
//! to the `AsyncRead` and `AsyncWrite` types.

use std::vec::Vec;

pub use futures_io::{AsyncRead, AsyncWrite, IoVec};

// Temporarily removed until AsyncBufRead is implemented
// pub use io::lines::{lines, Lines};
// pub use io::read_until::{read_until, ReadUntil};
// mod lines;
// mod read_until;

mod allow_std;
pub use self::allow_std::AllowStdIo;

mod copy_into;
pub use self::copy_into::CopyInto;

mod flush;
pub use self::flush::Flush;

mod read;
pub use self::read::Read;

mod read_exact;
pub use self::read_exact::ReadExact;

mod read_to_end;
pub use self::read_to_end::ReadToEnd;

mod close;
pub use self::close::Close;

mod split;
pub use self::split::{ReadHalf, WriteHalf};

mod window;
pub use self::window::Window;

mod write_all;
pub use self::write_all::WriteAll;

/// An extension trait which adds utility methods to `AsyncRead` types.
pub trait AsyncReadExt: AsyncRead {
    /// Creates a future which copies all the bytes from one object to another.
    ///
    /// The returned future will copy all the bytes read from this `AsyncRead` into the
    /// `writer` specified. This future will only complete once the `reader` has hit
    /// EOF and all bytes have been written to and flushed from the `writer`
    /// provided.
    ///
    /// On success the number of bytes is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 5];
    ///
    /// let bytes = {
    ///     let mut writer = Cursor::new(&mut output[..]);
    ///     await!(reader.copy_into(&mut writer))?
    /// };
    ///
    /// assert_eq!(bytes, 4);
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn copy_into<'a, W>(
        &'a mut self,
        writer: &'a mut W,
    ) -> CopyInto<'a, Self, W>
        where W: AsyncWrite,
    {
        CopyInto::new(self, writer)
    }

    /// Tries to read some bytes directly into the given `buf` in asynchronous
    /// manner, returning a future type.
    ///
    /// The returned future will resolve to the number of bytes read once the read
    /// operation is completed.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 5];
    ///
    /// let bytes = await!(reader.read(&mut output[..]))?;
    ///
    /// // This is only guaranteed to be 4 because `&[u8]` is a synchronous
    /// // reader. In a real system you could get anywhere from 1 to
    /// // `output.len()` bytes in a single read.
    /// assert_eq!(bytes, 4);
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> {
        Read::new(self, buf)
    }

    /// Creates a future which will read exactly enough bytes to fill `buf`,
    /// returning an error if end of file (EOF) is hit sooner.
    ///
    /// The returned future will resolve once the read operation is completed.
    ///
    /// In the case of an error the buffer and the object will be discarded, with
    /// the error yielded.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 4];
    ///
    /// await!(reader.read_exact(&mut output))?;
    ///
    /// assert_eq!(output, [1, 2, 3, 4]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    ///
    /// ## EOF is hit before `buf` is filled
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::{self, Cursor};
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = [0u8; 5];
    ///
    /// let result = await!(reader.read_exact(&mut output));
    ///
    /// assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
    /// # });
    /// ```
    fn read_exact<'a>(
        &'a mut self,
        buf: &'a mut [u8],
    ) -> ReadExact<'a, Self> {
        ReadExact::new(self, buf)
    }

    /// Creates a future which will read all the bytes from this `AsyncRead`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut output = Vec::with_capacity(4);
    ///
    /// await!(reader.read_to_end(&mut output))?;
    ///
    /// assert_eq!(output, vec![1, 2, 3, 4]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn read_to_end<'a>(
        &'a mut self,
        buf: &'a mut Vec<u8>,
    ) -> ReadToEnd<'a, Self> {
        ReadToEnd::new(self, buf)
    }

    /// Helper method for splitting this read/write object into two halves.
    ///
    /// The two halves returned implement the `AsyncRead` and `AsyncWrite`
    /// traits, respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncReadExt;
    /// use std::io::Cursor;
    ///
    /// let mut reader = Cursor::new([1, 2, 3, 4]);
    /// let mut buffer = [0, 0, 0, 0, 5, 6, 7, 8];
    /// let mut output = [0u8; 5];
    ///
    /// {
    ///     let mut writer = Cursor::new(&mut output[..]);
    ///     // Note that for `Cursor` the read and write halves share a single
    ///     // seek position. This may or may not be true for other types that
    ///     // implement both `AsyncRead` and `AsyncWrite`.
    ///     let buffer_cursor = Cursor::new(&mut buffer[..]);
    ///     let (mut buffer_reader, mut buffer_writer) = buffer_cursor.split();
    ///     await!(reader.copy_into(&mut buffer_writer))?;
    ///     await!(buffer_reader.copy_into(&mut writer))?;
    /// }
    ///
    /// assert_eq!(buffer, [1, 2, 3, 4, 5, 6, 7, 8]);
    /// assert_eq!(output, [5, 6, 7, 8, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
        where Self: AsyncWrite + Sized,
    {
        split::split(self)
    }
}

impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}

/// An extension trait which adds utility methods to `AsyncWrite` types.
pub trait AsyncWriteExt: AsyncWrite {
    /// Creates a future which will entirely flush this `AsyncWrite`.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::{AllowStdIo, AsyncWriteExt};
    /// use std::io::{BufWriter, Cursor};
    ///
    /// let mut output = [0u8; 5];
    ///
    /// {
    ///     let mut writer = Cursor::new(&mut output[..]);
    ///     let mut buffered = AllowStdIo::new(BufWriter::new(writer));
    ///     await!(buffered.write_all(&[1, 2]))?;
    ///     await!(buffered.write_all(&[3, 4]))?;
    ///     await!(buffered.flush())?;
    /// }
    ///
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn flush<'a>(&'a mut self) -> Flush<'a, Self> {
        Flush::new(self)
    }

    /// Creates a future which will entirely close this `AsyncWrite`.
    fn close<'a>(&'a mut self) -> Close<'a, Self> {
        Close::new(self)
    }

    /// Write data into this object.
    ///
    /// Creates a future that will write the entire contents of the buffer `buf` into
    /// this `AsyncWrite`.
    ///
    /// The returned future will not complete until all the data has been written.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(async_await, await_macro, futures_api)]
    /// # futures::executor::block_on(async {
    /// use futures::io::AsyncWriteExt;
    /// use std::io::Cursor;
    ///
    /// let mut output = [0u8; 5];
    ///
    /// {
    ///     let mut writer = Cursor::new(&mut output[..]);
    ///     await!(writer.write_all(&[1, 2, 3, 4]))?;
    /// }
    ///
    /// assert_eq!(output, [1, 2, 3, 4, 0]);
    /// # Ok::<(), Box<std::error::Error>>(()) }).unwrap();
    /// ```
    fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> {
        WriteAll::new(self, buf)
    }
}

impl<W: AsyncWrite + ?Sized> AsyncWriteExt for W {}
<|endoftext|>


<commit_before>// run-pass

fn main() {
	let x = 1;

	#[cfg(FALSE)]
	if false {
		x = 2;
	} else if true {
		x = 3;
	} else {
		x = 4;
	}
	assert_eq!(x, 1);
}
<commit_msg>Fix tabs<commit_after>// run-pass

fn main() {
    let x = 1;

    #[cfg(FALSE)]
    if false {
        x = 2;
    } else if true {
        x = 3;
    } else {
        x = 4;
    }
    assert_eq!(x, 1);
}
<|endoftext|>


<commit_before>//! ```
//! use glyph_brush::{BrushAction, BrushError, GlyphBrushBuilder, Section};
//!
//! # fn main() -> Result<(), glyph_brush::BrushError> {
//! let dejavu: &[u8] = include_bytes!("../../fonts/DejaVuSans.ttf");
//! let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(dejavu).build();
//! # let some_other_section = Section { text: "another", ..Section::default() };
//!
//! glyph_brush.queue(Section {
//!     text: "Hello glyph_brush",
//!     ..Section::default()
//! });
//! glyph_brush.queue(some_other_section);
//!
//! # let screen_dimensions = (1024, 768);
//! # let update_texture = |_, _| {};
//! # let into_vertex = |_| ();
//! match glyph_brush.process_queued(
//!     screen_dimensions,
//!     |rect, tex_data| update_texture(rect, tex_data),
//!     |vertex_data| into_vertex(vertex_data),
//! ) {
//!     Ok(BrushAction::Draw(vertices)) => {
//!         // Draw new vertices.
//!     }
//!     Ok(BrushAction::ReDraw) => {
//!         // Re-draw last frame's vertices unmodified.
//!     }
//!     Err(BrushError::TextureTooSmall { suggested }) => {
//!         // Enlarge texture + glyph_brush texture cache and retry.
//!     }
//! }
//! # Ok(())
//! # }
//! ```
mod glyph_brush;
mod glyph_calculator;
mod owned_section;
mod section;

pub use crate::{glyph_brush::*, glyph_calculator::*, owned_section::*, section::*};
pub use glyph_brush_layout::*;

use glyph_brush_layout::rusttype::*;

/// A "practically collision free" `Section` hasher
pub type DefaultSectionHasher = twox_hash::RandomXxHashBuilder;

#[test]
fn default_section_hasher() {
    use std::hash::{BuildHasher, Hash, Hasher};

    let section_a = Section {
        text: "Hovered Tile: Some((0, 0))",
        screen_position: (5.0, 60.0),
        scale: Scale { x: 20.0, y: 20.0 },
        color: [1.0, 1.0, 1.0, 1.0],
        ..<_>::default()
    };
    let section_b = Section {
        text: "Hovered Tile: Some((1, 0))",
        screen_position: (5.0, 60.0),
        scale: Scale { x: 20.0, y: 20.0 },
        color: [1.0, 1.0, 1.0, 1.0],
        ..<_>::default()
    };
    let hash = |s: &Section| {
        let s: VariedSection = s.into();
        let mut hasher = DefaultSectionHasher::default().build_hasher();
        s.hash(&mut hasher);
        hasher.finish()
    };
    assert_ne!(hash(&section_a), hash(&section_b));
}
<commit_msg>Workaround wasm rand issues<commit_after>//! ```
//! use glyph_brush::{BrushAction, BrushError, GlyphBrushBuilder, Section};
//!
//! # fn main() -> Result<(), glyph_brush::BrushError> {
//! let dejavu: &[u8] = include_bytes!("../../fonts/DejaVuSans.ttf");
//! let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(dejavu).build();
//! # let some_other_section = Section { text: "another", ..Section::default() };
//!
//! glyph_brush.queue(Section {
//!     text: "Hello glyph_brush",
//!     ..Section::default()
//! });
//! glyph_brush.queue(some_other_section);
//!
//! # let screen_dimensions = (1024, 768);
//! # let update_texture = |_, _| {};
//! # let into_vertex = |_| ();
//! match glyph_brush.process_queued(
//!     screen_dimensions,
//!     |rect, tex_data| update_texture(rect, tex_data),
//!     |vertex_data| into_vertex(vertex_data),
//! ) {
//!     Ok(BrushAction::Draw(vertices)) => {
//!         // Draw new vertices.
//!     }
//!     Ok(BrushAction::ReDraw) => {
//!         // Re-draw last frame's vertices unmodified.
//!     }
//!     Err(BrushError::TextureTooSmall { suggested }) => {
//!         // Enlarge texture + glyph_brush texture cache and retry.
//!     }
//! }
//! # Ok(())
//! # }
//! ```
mod glyph_brush;
mod glyph_calculator;
mod owned_section;
mod section;

pub use crate::{glyph_brush::*, glyph_calculator::*, owned_section::*, section::*};
pub use glyph_brush_layout::*;

use glyph_brush_layout::rusttype::*;

/// A "practically collision free" `Section` hasher
#[cfg(not(target_arch = "wasm32"))]
pub type DefaultSectionHasher = twox_hash::RandomXxHashBuilder;
// Work around for rand issues in wasm #61
#[cfg(target_arch = "wasm32")]
pub type DefaultSectionHasher = std::hash::BuildHasherDefault<twox_hash::XxHash>;

#[test]
fn default_section_hasher() {
    use std::hash::{BuildHasher, Hash, Hasher};

    let section_a = Section {
        text: "Hovered Tile: Some((0, 0))",
        screen_position: (5.0, 60.0),
        scale: Scale { x: 20.0, y: 20.0 },
        color: [1.0, 1.0, 1.0, 1.0],
        ..<_>::default()
    };
    let section_b = Section {
        text: "Hovered Tile: Some((1, 0))",
        screen_position: (5.0, 60.0),
        scale: Scale { x: 20.0, y: 20.0 },
        color: [1.0, 1.0, 1.0, 1.0],
        ..<_>::default()
    };
    let hash = |s: &Section| {
        let s: VariedSection = s.into();
        let mut hasher = DefaultSectionHasher::default().build_hasher();
        s.hash(&mut hasher);
        hasher.finish()
    };
    assert_ne!(hash(&section_a), hash(&section_b));
}
<|endoftext|>


<commit_before>use crate::command_prelude::*;

use cargo::ops::{self, CompileFilter, FilterRule, LibRule};

pub fn cli() -> App {
    subcommand("fix")
        .about("Automatically fix lint warnings reported by rustc")
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg_package_spec(
            "Package(s) to fix",
            "Fix all packages in the workspace",
            "Exclude packages from the fixes",
        )
        .arg_jobs()
        .arg_targets_all(
            "Fix only this package's library",
            "Fix only the specified binary",
            "Fix all binaries",
            "Fix only the specified example",
            "Fix all examples",
            "Fix only the specified test target",
            "Fix all tests",
            "Fix only the specified bench target",
            "Fix all benches",
            "Fix all targets (default)",
        )
        .arg_release("Fix artifacts in release mode, with optimizations")
        .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
        .arg_features()
        .arg_target_triple("Fix for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .arg(
            Arg::with_name("broken-code")
                .long("broken-code")
                .help("Fix code even if it already has compiler errors"),
        )
        .arg(
            Arg::with_name("edition")
                .long("edition")
                .help("Fix in preparation for the next edition"),
        )
        .arg(
            // This is a deprecated argument, we'll want to phase it out
            // eventually.
            Arg::with_name("prepare-for")
                .long("prepare-for")
                .help("Fix warnings in preparation of an edition upgrade")
                .takes_value(true)
                .possible_values(&["2018"])
                .conflicts_with("edition")
                .hidden(true),
        )
        .arg(
            Arg::with_name("idioms")
                .long("edition-idioms")
                .help("Fix warnings to migrate to the idioms of an edition"),
        )
        .arg(
            Arg::with_name("allow-no-vcs")
                .long("allow-no-vcs")
                .help("Fix code even if a VCS was not detected"),
        )
        .arg(
            Arg::with_name("allow-dirty")
                .long("allow-dirty")
                .help("Fix code even if the working directory is dirty"),
        )
        .arg(
            Arg::with_name("allow-staged")
                .long("allow-staged")
                .help("Fix code even if the working directory has staged changes"),
        )
        .arg(
            Arg::with_name("clippy")
                .long("clippy")
                .help("Get fix suggestions from clippy instead of check")
                .hidden(true)
        )
        .arg(
            Arg::with_name("clippy-args")
                .long("clippy-args")
                .help("Args to pass through to clippy, implies --clippy")
                .hidden(true)
                .multiple(true)
                .number_of_values(1)
        )
        .after_help(
            "\
This Cargo subcommand will automatically take rustc's suggestions from
diagnostics like warnings and apply them to your source code. This is intended
to help automate tasks that rustc itself already knows how to tell you to fix!
The `cargo fix` subcommand is also being developed for the Rust 2018 edition
to provide code the ability to easily opt-in to the new edition without having
to worry about any breakage.

Executing `cargo fix` will under the hood execute `cargo check`. Any warnings
applicable to your crate will be automatically fixed (if possible) and all
remaining warnings will be displayed when the check process is finished. For
example if you'd like to prepare for the 2018 edition, you can do so by
executing:

    cargo fix --edition

which behaves the same as `cargo check --all-targets`. Similarly if you'd like
to fix code for different platforms you can do:

    cargo fix --edition --target x86_64-pc-windows-gnu

or if your crate has optional features:

    cargo fix --edition --no-default-features --features foo

If you encounter any problems with `cargo fix` or otherwise have any questions
or feature requests please don't hesitate to file an issue at
https://github.com/rust-lang/cargo
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;
    let test = match args.value_of("profile") {
        Some("test") => true,
        None => false,
        Some(profile) => {
            let err = failure::format_err!(
                "unknown profile: `{}`, only `test` is \
                 currently supported",
                profile
            );
            return Err(CliError::new(err, 101));
        }
    };
    let mode = CompileMode::Check { test };

    // Unlike other commands default `cargo fix` to all targets to fix as much
    // code as we can.
    let mut opts = args.compile_options(config, mode, Some(&ws))?;

    let clippy_args = args.values_of_lossy("clippy-args");
    let use_clippy = args.is_present("clippy") || clippy_args.is_some();

    if use_clippy && !config.cli_unstable().unstable_options {
        return Err(failure::format_err!(
            "`cargo fix --clippy` is unstable, pass `-Z unstable-options` to enable it"
        )
        .into());
    }

    if let CompileFilter::Default { .. } = opts.filter {
        opts.filter = CompileFilter::Only {
            all_targets: true,
            lib: LibRule::Default,
            bins: FilterRule::All,
            examples: FilterRule::All,
            benches: FilterRule::All,
            tests: FilterRule::All,
        }
    }
    ops::fix(
        &ws,
        &mut ops::FixOptions {
            edition: args.is_present("edition"),
            prepare_for: args.value_of("prepare-for"),
            idioms: args.is_present("idioms"),
            compile_opts: opts,
            allow_dirty: args.is_present("allow-dirty"),
            allow_no_vcs: args.is_present("allow-no-vcs"),
            allow_staged: args.is_present("allow-staged"),
            broken_code: args.is_present("broken-code"),
            use_clippy,
            clippy_args,
        },
    )?;
    Ok(())
}
<commit_msg>appease cargo fmt<commit_after>use crate::command_prelude::*;

use cargo::ops::{self, CompileFilter, FilterRule, LibRule};

pub fn cli() -> App {
    subcommand("fix")
        .about("Automatically fix lint warnings reported by rustc")
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg_package_spec(
            "Package(s) to fix",
            "Fix all packages in the workspace",
            "Exclude packages from the fixes",
        )
        .arg_jobs()
        .arg_targets_all(
            "Fix only this package's library",
            "Fix only the specified binary",
            "Fix all binaries",
            "Fix only the specified example",
            "Fix all examples",
            "Fix only the specified test target",
            "Fix all tests",
            "Fix only the specified bench target",
            "Fix all benches",
            "Fix all targets (default)",
        )
        .arg_release("Fix artifacts in release mode, with optimizations")
        .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
        .arg_features()
        .arg_target_triple("Fix for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .arg(
            Arg::with_name("broken-code")
                .long("broken-code")
                .help("Fix code even if it already has compiler errors"),
        )
        .arg(
            Arg::with_name("edition")
                .long("edition")
                .help("Fix in preparation for the next edition"),
        )
        .arg(
            // This is a deprecated argument, we'll want to phase it out
            // eventually.
            Arg::with_name("prepare-for")
                .long("prepare-for")
                .help("Fix warnings in preparation of an edition upgrade")
                .takes_value(true)
                .possible_values(&["2018"])
                .conflicts_with("edition")
                .hidden(true),
        )
        .arg(
            Arg::with_name("idioms")
                .long("edition-idioms")
                .help("Fix warnings to migrate to the idioms of an edition"),
        )
        .arg(
            Arg::with_name("allow-no-vcs")
                .long("allow-no-vcs")
                .help("Fix code even if a VCS was not detected"),
        )
        .arg(
            Arg::with_name("allow-dirty")
                .long("allow-dirty")
                .help("Fix code even if the working directory is dirty"),
        )
        .arg(
            Arg::with_name("allow-staged")
                .long("allow-staged")
                .help("Fix code even if the working directory has staged changes"),
        )
        .arg(
            Arg::with_name("clippy")
                .long("clippy")
                .help("Get fix suggestions from clippy instead of check")
                .hidden(true),
        )
        .arg(
            Arg::with_name("clippy-args")
                .long("clippy-args")
                .help("Args to pass through to clippy, implies --clippy")
                .hidden(true)
                .multiple(true)
                .number_of_values(1),
        )
        .after_help(
            "\
This Cargo subcommand will automatically take rustc's suggestions from
diagnostics like warnings and apply them to your source code. This is intended
to help automate tasks that rustc itself already knows how to tell you to fix!
The `cargo fix` subcommand is also being developed for the Rust 2018 edition
to provide code the ability to easily opt-in to the new edition without having
to worry about any breakage.

Executing `cargo fix` will under the hood execute `cargo check`. Any warnings
applicable to your crate will be automatically fixed (if possible) and all
remaining warnings will be displayed when the check process is finished. For
example if you'd like to prepare for the 2018 edition, you can do so by
executing:

    cargo fix --edition

which behaves the same as `cargo check --all-targets`. Similarly if you'd like
to fix code for different platforms you can do:

    cargo fix --edition --target x86_64-pc-windows-gnu

or if your crate has optional features:

    cargo fix --edition --no-default-features --features foo

If you encounter any problems with `cargo fix` or otherwise have any questions
or feature requests please don't hesitate to file an issue at
https://github.com/rust-lang/cargo
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;
    let test = match args.value_of("profile") {
        Some("test") => true,
        None => false,
        Some(profile) => {
            let err = failure::format_err!(
                "unknown profile: `{}`, only `test` is \
                 currently supported",
                profile
            );
            return Err(CliError::new(err, 101));
        }
    };
    let mode = CompileMode::Check { test };

    // Unlike other commands default `cargo fix` to all targets to fix as much
    // code as we can.
    let mut opts = args.compile_options(config, mode, Some(&ws))?;

    let clippy_args = args.values_of_lossy("clippy-args");
    let use_clippy = args.is_present("clippy") || clippy_args.is_some();

    if use_clippy && !config.cli_unstable().unstable_options {
        return Err(failure::format_err!(
            "`cargo fix --clippy` is unstable, pass `-Z unstable-options` to enable it"
        )
        .into());
    }

    if let CompileFilter::Default { .. } = opts.filter {
        opts.filter = CompileFilter::Only {
            all_targets: true,
            lib: LibRule::Default,
            bins: FilterRule::All,
            examples: FilterRule::All,
            benches: FilterRule::All,
            tests: FilterRule::All,
        }
    }
    ops::fix(
        &ws,
        &mut ops::FixOptions {
            edition: args.is_present("edition"),
            prepare_for: args.value_of("prepare-for"),
            idioms: args.is_present("idioms"),
            compile_opts: opts,
            allow_dirty: args.is_present("allow-dirty"),
            allow_no_vcs: args.is_present("allow-no-vcs"),
            allow_staged: args.is_present("allow-staged"),
            broken_code: args.is_present("broken-code"),
            use_clippy,
            clippy_args,
        },
    )?;
    Ok(())
}
<|endoftext|>


<commit_before>#[allow(unused_imports)]
#[macro_use]
extern crate log;
extern crate libc;
extern crate env_logger;
extern crate catfs;
extern crate rand;
extern crate fuse;
extern crate xattr;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Write};
use std::process::Command;
use std::path::{Path, PathBuf};
use std::os::unix::fs::FileExt;

use rand::{thread_rng, Rng};

use catfs::CatFS;
use catfs::catfs::error;

#[macro_use]
mod test_suite;

trait Fixture {
    fn setup() -> error::Result<Self>
    where
        Self: std::marker::Sized;
    fn teardown(self) -> error::Result<()>;
}

struct CatFSTests<'a> {
    prefix: PathBuf,
    mnt: PathBuf,
    src: *const PathBuf,
    cache: *const PathBuf,
    session: Option<fuse::BackgroundSession<'a>>,
}

fn copy_all(dir1: &AsRef<Path>, dir2: &AsRef<Path>) -> error::Result<()> {
    fs::create_dir(dir2)?;

    for entry in fs::read_dir(dir1)? {
        let entry = entry?;
        let to = dir2.as_ref().join(entry.file_name());

        if entry.file_type()?.is_dir() {
            copy_all(&entry.path(), &to)?;
        } else {
            fs::copy(entry.path(), to)?;
        }
    }

    return Ok(());
}

impl<'a> CatFSTests<'a> {
    fn get_orig_dir() -> PathBuf {
        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        return PathBuf::from(manifest).join("tests/resources");
    }

    fn get_from(&self) -> PathBuf {
        return self.prefix.join("resources");
    }

    fn get_cache(&self) -> PathBuf {
        return self.prefix.join("cache");
    }

    fn extend(&self, s: *const PathBuf) -> &'static PathBuf {
        return unsafe { std::mem::transmute(s) };
    }

    fn mount(&self) -> error::Result<fuse::BackgroundSession<'a>> {
        let src = self.extend(self.src);
        let cache = self.extend(self.cache);
        let fs = CatFS::new(src, cache)?;

        return Ok(unsafe { fuse::spawn_mount(fs, &self.mnt, &[])? });
    }
}

impl<'a> Fixture for CatFSTests<'a> {
    fn setup() -> error::Result<CatFSTests<'a>> {
        #[allow(unused_must_use)] env_logger::init();

        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        let prefix = PathBuf::from(manifest).join("target/test").join(
            thread_rng().gen_ascii_chars().take(10).collect::<String>(),
        );
        let mnt = prefix.join("mnt");
        let resources = prefix.join("resources");
        let cache = prefix.join("cache");

        fs::create_dir_all(&mnt)?;
        fs::create_dir_all(&cache)?;

        fs::create_dir(CatFSTests::get_orig_dir().join("dir2"));
        copy_all(&CatFSTests::get_orig_dir(), &resources)?;

        let mut t = CatFSTests {
            prefix: prefix,
            mnt: mnt,
            src: &resources as *const PathBuf,
            cache: &cache as *const PathBuf,
            session: Default::default(),
        };

        std::mem::forget(resources);
        std::mem::forget(cache);

        t.session = Some(t.mount()?);

        return Ok(t);
    }

    fn teardown(self) -> error::Result<()> {
        {
            // move out the session to let us umount first
            #[allow(unused_variables)]
            let session = self.session;
        }
        fs::remove_dir_all(&self.prefix)?;
        // TODO do I need to free self.src/cache?
        return Ok(());
    }
}

fn diff(dir1: &AsRef<Path>, dir2: &AsRef<Path>) {
    let status = Command::new("diff")
        .arg("-ru")
        .arg(dir1.as_ref().as_os_str())
        .arg(dir2.as_ref().as_os_str())
        .status()
        .expect("failed to execute `diff'");
    assert!(status.success());
}

unit_tests!{
    fn read_one(f: &CatFSTests) {
        let mut s = String::new();
        File::open(f.mnt.join("dir1/file1")).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file1\n");
    }

    fn read_all(f: &CatFSTests) {
        diff(&CatFSTests::get_orig_dir(), &f.mnt);
    }

    fn create(f: &CatFSTests) {
        {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(Path::new(&f.mnt).join("foo")).unwrap();
            fh.write_all(b"hello world").unwrap();
        }

        fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        diff(&f.get_from(), &f.mnt);
    }

    fn large_write(f: &CatFSTests) {
        let mut of=OsString::from("of=");
        of.push(f.mnt.join("foo"));
        let status = Command::new("dd")
            .arg("if=/dev/zero").arg(of)
            .arg("bs=1M").arg("count=100")
            .status().expect("failed to execute `dd'");
        assert!(status.success());

        let foo = fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        assert_eq!(foo.len(), 100 * 1024 * 1024);
        diff(&f.get_from(), &f.mnt);
    }

    fn large_dir(f: &CatFSTests) {
        let dir2 = Path::new(&f.mnt).join("dir2");
        for i in 1..1001 {
            let _fh = OpenOptions::new().write(true).create(true)
                .open(dir2.join(format!("{}", i))).unwrap();
        }

        let mut i = 0;
        let mut total = 0;
        for entry in fs::read_dir(dir2).unwrap() {
            i += 1;
            total += entry.unwrap().file_name().to_str().unwrap().parse().unwrap();
        }
        assert_eq!(i, 1000);
        assert_eq!(total, (1000 * (1000 + 1)) / 2);
        diff(&f.get_from(), &f.mnt);
    }

    fn read_modify_write(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let fh = OpenOptions::new().write(true).open(&file1).unwrap();
            let nbytes = fh.write_at("*".as_bytes(), 9).unwrap();
            assert_eq!(nbytes, 1);
        }

        let mut s = String::new();
        File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file*\n");
        diff(&f.get_from(), &f.mnt);
    }

    fn write_twice(f: &CatFSTests) {
        for _ in 0..2 {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(Path::new(&f.mnt).join("foo")).unwrap();
            fh.write_all(b"hello world").unwrap();
        }

        fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        diff(&f.get_from(), &f.mnt);
    }

    fn unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
        diff(&f.get_from(), &f.mnt);
    }

    fn read_unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let mut s = String::new();
            File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
            assert_eq!(s, "dir1/file1\n");
        }
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
        diff(&f.get_from(), &f.mnt);
    }

    fn mkdir(f: &CatFSTests) {
        let foo = f.mnt.join("foo");
        fs::create_dir(&foo).unwrap();
    }

    fn rmdir(f: &CatFSTests) {
        let dir2 = f.mnt.join("dir2");
        fs::remove_dir(&dir2).unwrap();
        if let Err(e) = fs::symlink_metadata(&dir2) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", dir2);
        }
        diff(&f.get_from(), &f.mnt);
    }

    fn rmdir_not_empty(f: &CatFSTests) {
        let dir1 = f.mnt.join("dir1");
        if let Err(e) = fs::remove_dir(&dir1) {
            assert_eq!(e.raw_os_error().unwrap(), libc::ENOTEMPTY);
        } else {
            panic!("{:?} deleted", dir1);
        }
    }

    fn check_dirty(f: &CatFSTests) {
        let foo = f.mnt.join("foo");
        let foo_cache = f.get_cache().join("foo");
        {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(&foo).unwrap();
            fh.write_all(b"hello world").unwrap();

            // at this point the file is NOT flushed yet, so pristine
            // should not be set
            assert!(xattr::get(&foo_cache, "user.catfs.pristine").unwrap().is_none());
        }

        let v = xattr::get(&foo_cache, "user.catfs.pristine").unwrap().unwrap();
        assert_eq!(v, catfs::catfs::file::PRISTINE);

        {
            let mut fh = OpenOptions::new().write(true)
                .open(&foo).unwrap();
            fh.write_all(b"hello world").unwrap();

            // at this point the file is NOT flushed yet, so pristine
            // should be dirty
            let v = xattr::get(&foo_cache, "user.catfs.pristine").unwrap().unwrap();
            assert_eq!(v, catfs::catfs::file::DIRTY);
        }

        let v = xattr::get(&foo_cache, "user.catfs.pristine").unwrap().unwrap();
        assert_eq!(v, catfs::catfs::file::PRISTINE);
    }
}
<commit_msg>add test to check that cache is valid just after write<commit_after>#[allow(unused_imports)]
#[macro_use]
extern crate log;
extern crate libc;
extern crate env_logger;
extern crate catfs;
extern crate rand;
extern crate fuse;
extern crate xattr;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Write};
use std::process::Command;
use std::path::{Path, PathBuf};
use std::os::unix::fs::FileExt;

use rand::{thread_rng, Rng};

use catfs::CatFS;
use catfs::catfs::error;

#[macro_use]
mod test_suite;

trait Fixture {
    fn setup() -> error::Result<Self>
    where
        Self: std::marker::Sized;
    fn teardown(self) -> error::Result<()>;
}

struct CatFSTests<'a> {
    prefix: PathBuf,
    mnt: PathBuf,
    src: *const PathBuf,
    cache: *const PathBuf,
    session: Option<fuse::BackgroundSession<'a>>,
}

fn copy_all(dir1: &AsRef<Path>, dir2: &AsRef<Path>) -> error::Result<()> {
    fs::create_dir(dir2)?;

    for entry in fs::read_dir(dir1)? {
        let entry = entry?;
        let to = dir2.as_ref().join(entry.file_name());

        if entry.file_type()?.is_dir() {
            copy_all(&entry.path(), &to)?;
        } else {
            fs::copy(entry.path(), to)?;
        }
    }

    return Ok(());
}

impl<'a> CatFSTests<'a> {
    fn get_orig_dir() -> PathBuf {
        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        return PathBuf::from(manifest).join("tests/resources");
    }

    fn get_from(&self) -> PathBuf {
        return self.prefix.join("resources");
    }

    fn get_cache(&self) -> PathBuf {
        return self.prefix.join("cache");
    }

    fn extend(&self, s: *const PathBuf) -> &'static PathBuf {
        return unsafe { std::mem::transmute(s) };
    }

    fn mount(&self) -> error::Result<fuse::BackgroundSession<'a>> {
        let src = self.extend(self.src);
        let cache = self.extend(self.cache);
        let fs = CatFS::new(src, cache)?;

        return Ok(unsafe { fuse::spawn_mount(fs, &self.mnt, &[])? });
    }
}

impl<'a> Fixture for CatFSTests<'a> {
    fn setup() -> error::Result<CatFSTests<'a>> {
        #[allow(unused_must_use)] env_logger::init();

        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        let prefix = PathBuf::from(manifest).join("target/test").join(
            thread_rng().gen_ascii_chars().take(10).collect::<String>(),
        );
        let mnt = prefix.join("mnt");
        let resources = prefix.join("resources");
        let cache = prefix.join("cache");

        fs::create_dir_all(&mnt)?;
        fs::create_dir_all(&cache)?;

        fs::create_dir(CatFSTests::get_orig_dir().join("dir2"));
        copy_all(&CatFSTests::get_orig_dir(), &resources)?;

        let mut t = CatFSTests {
            prefix: prefix,
            mnt: mnt,
            src: &resources as *const PathBuf,
            cache: &cache as *const PathBuf,
            session: Default::default(),
        };

        std::mem::forget(resources);
        std::mem::forget(cache);

        t.session = Some(t.mount()?);

        return Ok(t);
    }

    fn teardown(self) -> error::Result<()> {
        {
            // move out the session to let us umount first
            #[allow(unused_variables)]
            let session = self.session;
        }
        fs::remove_dir_all(&self.prefix)?;
        // TODO do I need to free self.src/cache?
        return Ok(());
    }
}

fn diff(dir1: &AsRef<Path>, dir2: &AsRef<Path>) {
    let status = Command::new("diff")
        .arg("-ru")
        .arg(dir1.as_ref().as_os_str())
        .arg(dir2.as_ref().as_os_str())
        .status()
        .expect("failed to execute `diff'");
    assert!(status.success());
}

unit_tests!{
    fn read_one(f: &CatFSTests) {
        let mut s = String::new();
        File::open(f.mnt.join("dir1/file1")).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file1\n");
    }

    fn read_all(f: &CatFSTests) {
        diff(&CatFSTests::get_orig_dir(), &f.mnt);
    }

    fn create(f: &CatFSTests) {
        {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(Path::new(&f.mnt).join("foo")).unwrap();
            fh.write_all(b"hello world").unwrap();
        }

        fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        diff(&f.get_from(), &f.mnt);
    }

    fn large_write(f: &CatFSTests) {
        let mut of=OsString::from("of=");
        of.push(f.mnt.join("foo"));
        let status = Command::new("dd")
            .arg("if=/dev/zero").arg(of)
            .arg("bs=1M").arg("count=100")
            .status().expect("failed to execute `dd'");
        assert!(status.success());

        let foo = fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        assert_eq!(foo.len(), 100 * 1024 * 1024);
        diff(&f.get_from(), &f.mnt);
    }

    fn large_dir(f: &CatFSTests) {
        let dir2 = Path::new(&f.mnt).join("dir2");
        for i in 1..1001 {
            let _fh = OpenOptions::new().write(true).create(true)
                .open(dir2.join(format!("{}", i))).unwrap();
        }

        let mut i = 0;
        let mut total = 0;
        for entry in fs::read_dir(dir2).unwrap() {
            i += 1;
            total += entry.unwrap().file_name().to_str().unwrap().parse().unwrap();
        }
        assert_eq!(i, 1000);
        assert_eq!(total, (1000 * (1000 + 1)) / 2);
        diff(&f.get_from(), &f.mnt);
    }

    fn read_modify_write(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let fh = OpenOptions::new().write(true).open(&file1).unwrap();
            let nbytes = fh.write_at("*".as_bytes(), 9).unwrap();
            assert_eq!(nbytes, 1);
        }

        let mut s = String::new();
        File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file*\n");
        diff(&f.get_from(), &f.mnt);
    }

    fn write_twice(f: &CatFSTests) {
        for _ in 0..2 {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(Path::new(&f.mnt).join("foo")).unwrap();
            fh.write_all(b"hello world").unwrap();
        }

        fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        diff(&f.get_from(), &f.mnt);
    }

    fn unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
        diff(&f.get_from(), &f.mnt);
    }

    fn read_unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let mut s = String::new();
            File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
            assert_eq!(s, "dir1/file1\n");
        }
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
        diff(&f.get_from(), &f.mnt);
    }

    fn mkdir(f: &CatFSTests) {
        let foo = f.mnt.join("foo");
        fs::create_dir(&foo).unwrap();
    }

    fn rmdir(f: &CatFSTests) {
        let dir2 = f.mnt.join("dir2");
        fs::remove_dir(&dir2).unwrap();
        if let Err(e) = fs::symlink_metadata(&dir2) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", dir2);
        }
        diff(&f.get_from(), &f.mnt);
    }

    fn rmdir_not_empty(f: &CatFSTests) {
        let dir1 = f.mnt.join("dir1");
        if let Err(e) = fs::remove_dir(&dir1) {
            assert_eq!(e.raw_os_error().unwrap(), libc::ENOTEMPTY);
        } else {
            panic!("{:?} deleted", dir1);
        }
    }

    fn check_dirty(f: &CatFSTests) {
        let foo = f.mnt.join("foo");
        let foo_cache = f.get_cache().join("foo");
        {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(&foo).unwrap();
            fh.write_all(b"hello world").unwrap();

            // at this point the file is NOT flushed yet, so pristine
            // should not be set
            assert!(xattr::get(&foo_cache, "user.catfs.pristine").unwrap().is_none());
        }

        let v = xattr::get(&foo_cache, "user.catfs.pristine").unwrap().unwrap();
        assert_eq!(v, catfs::catfs::file::PRISTINE);

        {
            let mut fh = OpenOptions::new().write(true)
                .open(&foo).unwrap();
            fh.write_all(b"hello world").unwrap();

            // at this point the file is NOT flushed yet, so pristine
            // should be dirty
            let v = xattr::get(&foo_cache, "user.catfs.pristine").unwrap().unwrap();
            assert_eq!(v, catfs::catfs::file::DIRTY);
        }

        let v = xattr::get(&foo_cache, "user.catfs.pristine").unwrap().unwrap();
        assert_eq!(v, catfs::catfs::file::PRISTINE);
    }

    fn create_pristine(f: &CatFSTests) {
        let foo = Path::new(&f.mnt).join("foo");
        {
            let mut wh = OpenOptions::new().write(true).create(true)
                .open(&foo).unwrap();
            wh.write_all(b"hello world").unwrap();

            // we haven't closed the file yet, but we should still be
            // reading from it
            let mut contents = String::new();
            let mut rh = OpenOptions::new().read(true).open(&foo).unwrap();
            rh.read_to_string(&mut contents).unwrap();
            assert_eq!(contents, "hello world");
        }
    }
}
<|endoftext|>


<commit_before>use cairo;

use librsvg::{rsvg_convert_only::LegacySize, CairoRenderer};

use crate::utils::load_svg;

#[test]
fn just_viewbox_uses_viewbox_size() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 200"/>
"#,
    )
        .unwrap();

    assert_eq!(
        CairoRenderer::new(&svg).legacy_layer_geometry(None).unwrap(),
        (cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 200.0,
        },
         cairo::Rectangle {
             x: 0.0,
             y: 0.0,
             width: 100.0,
             height: 200.0,
         })
    );
}

#[test]
fn no_intrinsic_size_uses_element_geometries() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="20" width="30" height="40" fill="black"/>
</svg>
"#,
    )
        .unwrap();

    assert_eq!(
        CairoRenderer::new(&svg).legacy_layer_geometry(None).unwrap(),
        (cairo::Rectangle {
            x: 10.0,
            y: 20.0,
            width: 30.0,
            height: 40.0,
        },
         cairo::Rectangle {
             x: 10.0,
             y: 20.0,
             width: 30.0,
             height: 40.0,
         })
    );
}

#[test]
fn hundred_percent_width_height_uses_viewbox() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 100 200"/>
"#,
    )
        .unwrap();

    assert_eq!(
        CairoRenderer::new(&svg).legacy_layer_geometry(None).unwrap(),
        (cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 200.0,
        },
         cairo::Rectangle {
             x: 0.0,
             y: 0.0,
             width: 100.0,
             height: 200.0,
         })
    );
}
<commit_msg>Test for 100% width/height with no viewBox<commit_after>use cairo;

use librsvg::{rsvg_convert_only::LegacySize, CairoRenderer};

use crate::utils::load_svg;

#[test]
fn just_viewbox_uses_viewbox_size() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 200"/>
"#,
    )
        .unwrap();

    assert_eq!(
        CairoRenderer::new(&svg).legacy_layer_geometry(None).unwrap(),
        (cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 200.0,
        },
         cairo::Rectangle {
             x: 0.0,
             y: 0.0,
             width: 100.0,
             height: 200.0,
         })
    );
}

#[test]
fn no_intrinsic_size_uses_element_geometries() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="20" width="30" height="40" fill="black"/>
</svg>
"#,
    )
        .unwrap();

    assert_eq!(
        CairoRenderer::new(&svg).legacy_layer_geometry(None).unwrap(),
        (cairo::Rectangle {
            x: 10.0,
            y: 20.0,
            width: 30.0,
            height: 40.0,
        },
         cairo::Rectangle {
             x: 10.0,
             y: 20.0,
             width: 30.0,
             height: 40.0,
         })
    );
}

#[test]
fn hundred_percent_width_height_uses_viewbox() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 100 200"/>
"#,
    )
        .unwrap();

    assert_eq!(
        CairoRenderer::new(&svg).legacy_layer_geometry(None).unwrap(),
        (cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 200.0,
        },
         cairo::Rectangle {
             x: 0.0,
             y: 0.0,
             width: 100.0,
             height: 200.0,
         })
    );
}

#[test]
fn hundred_percent_width_height_no_viewbox_uses_element_geometries() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  <rect x="10" y="20" width="30" height="40" fill="black"/>
</svg>
"#,
    )
        .unwrap();

    assert_eq!(
        CairoRenderer::new(&svg).legacy_layer_geometry(None).unwrap(),
        (cairo::Rectangle {
            x: 10.0,
            y: 20.0,
            width: 30.0,
            height: 40.0,
        },
         cairo::Rectangle {
             x: 10.0,
             y: 20.0,
             width: 30.0,
             height: 40.0,
         })
    );
}
<|endoftext|>


<commit_before>use sled;

use std::ffi::CString;
use std::mem;
use std::ptr;
use std::slice;

use libc::*;

use sled::{Config, Db, Iter};

fn leak_buf(v: Vec<u8>, vallen: *mut size_t) -> *mut c_char {
    unsafe {
        *vallen = v.len();
    }
    let mut bsv = v.into_boxed_slice();
    let val = bsv.as_mut_ptr() as *mut _;
    mem::forget(bsv);
    val
}

/// Create a new configuration.
#[no_mangle]
pub unsafe extern "C" fn sled_create_config() -> *mut Config {
    Box::into_raw(Box::new(Config::new()))
}

/// Destroy a configuration.
#[no_mangle]
pub unsafe extern "C" fn sled_free_config(config: *mut Config) {
    drop(Box::from_raw(config));
}

/// Set the configured file path. The caller is responsible for freeing the path
/// string after calling this (it is copied in this function).
#[no_mangle]
pub unsafe extern "C" fn sled_config_set_path(
    config: *mut Config,
    path: *const c_char,
) {
    let c_str = CString::from_raw(path as *mut _);
    let value = c_str.into_string().unwrap();

    (*config).path(value);
}

/// Configure read-only mode.
#[no_mangle]
pub unsafe extern "C" fn sled_config_read_only(
    config: *mut Config,
    read_only: c_uchar,
) {
    (*config).read_only(read_only == 1);
}

/// Set the configured cache capacity in bytes.
#[no_mangle]
pub unsafe extern "C" fn sled_config_set_cache_capacity(
    config: *mut Config,
    capacity: size_t,
) {
    (*config).cache_capacity(capacity as u64);
}

/// Configure the use of the zstd compression library.
#[no_mangle]
pub unsafe extern "C" fn sled_config_use_compression(
    config: *mut Config,
    use_compression: c_uchar,
) {
    (*config).use_compression(use_compression == 1);
}

/// Set the configured IO buffer flush interval in milliseconds.
#[no_mangle]
pub unsafe extern "C" fn sled_config_flush_every_ms(
    config: *mut Config,
    flush_every: c_int,
) {
    let val = if flush_every <= 0 { None } else { Some(flush_every as u64) };
    (*config).flush_every_ms(val);
}

/// Open a sled lock-free log-structured tree. Consumes the passed-in config.
#[no_mangle]
pub unsafe extern "C" fn sled_open_db(config: *mut Config) -> *mut Db {
    let config = Box::from_raw(config);
    Box::into_raw(Box::new(config.open().unwrap()))
}

/// Close a sled lock-free log-structured tree.
#[no_mangle]
pub unsafe extern "C" fn sled_close(db: *mut Db) {
    drop(Box::from_raw(db));
}

/// Free a buffer originally allocated by sled.
#[no_mangle]
pub unsafe extern "C" fn sled_free_buf(buf: *mut c_char, sz: size_t) {
    drop(Vec::from_raw_parts(buf, sz, sz));
}

/// Free an iterator.
#[no_mangle]
pub unsafe extern "C" fn sled_free_iter(iter: *mut Iter) {
    drop(Box::from_raw(iter));
}

/// Set a key to a value. Does not take ownership over the
/// passed-in key and value.
#[no_mangle]
pub unsafe extern "C" fn sled_set(
    db: *mut Db,
    key: *const c_uchar,
    keylen: size_t,
    val: *const c_uchar,
    vallen: size_t,
) {
    let k = IVec::from(slice::from_raw_parts(key, keylen));
    let v = IVec::from(slice::from_raw_parts(val, vallen));
    (*db).insert(k, v).unwrap();
}

/// Get the value of a key.
/// Caller is responsible for freeing the returned value with `sled_free_buf` if
/// it's non-null.
#[no_mangle]
pub unsafe extern "C" fn sled_get(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
    vallen: *mut size_t,
) -> *mut c_char {
    let k = slice::from_raw_parts(key as *const u8, keylen);
    let res = (*db).get(k);
    match res {
        Ok(Some(v)) => leak_buf(v.to_vec(), vallen),
        Ok(None) => ptr::null_mut(),
        // TODO proper error propagation
        Err(e) => panic!("{:?}", e),
    }
}

/// Delete the value of a key.
#[no_mangle]
pub unsafe extern "C" fn sled_del(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
) {
    let k = slice::from_raw_parts(key as *const u8, keylen);
    (*db).remove(k).unwrap();
}

/// Compare and swap.
/// Returns 1 if successful, 0 if unsuccessful.
/// Otherwise sets `actual_val` and `actual_vallen` to the current value,
/// which must be freed using `sled_free_buf` by the caller if non-null.
/// `actual_val` will be null and `actual_vallen` 0 if the current value is not
/// set.
#[no_mangle]
pub unsafe extern "C" fn sled_compare_and_swap(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
    old_val: *const c_uchar,
    old_vallen: size_t,
    new_val: *const c_uchar,
    new_vallen: size_t,
    actual_val: *mut *const c_uchar,
    actual_vallen: *mut size_t,
) -> c_uchar {
    let k = slice::from_raw_parts(key as *const u8, keylen).to_vec();

    let old = if old_vallen == 0 {
        None
    } else {
        let old_slice = slice::from_raw_parts(old_val as *const u8, old_vallen);
        let copy = old_slice.to_vec();
        Some(copy)
    };

    let new = if new_vallen == 0 {
        None
    } else {
        let new_slice = slice::from_raw_parts(new_val as *const u8, new_vallen);
        let copy = new_slice.to_vec();
        Some(copy)
    };

    let res = (*db).compare_and_swap(k, old, new);

    match res {
        Ok(Ok(())) => 1,
        Ok(Err(sled::CompareAndSwapError { current: None, .. })) => {
            *actual_vallen = 0;
            0
        }
        Ok(Err(sled::CompareAndSwapError { current: Some(v), .. })) => {
            *actual_val = leak_buf(v.to_vec(), actual_vallen) as *const u8;
            0
        }
        // TODO proper error propagation
        Err(e) => panic!("{:?}", e),
    }
}

/// Iterate over tuples which have specified key prefix.
/// Caller is responsible for freeing the returned iterator with
/// `sled_free_iter`.
#[no_mangle]
pub unsafe extern "C" fn sled_scan_prefix(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
) -> *mut Iter {
    let k = slice::from_raw_parts(key as *const u8, keylen);
    Box::into_raw(Box::new((*db).scan_prefix(k)))
}

/// Get they next kv pair from an iterator.
/// Caller is responsible for freeing the key and value with `sled_free_buf`.
/// Returns 0 when exhausted.
#[no_mangle]
pub unsafe extern "C" fn sled_iter_next(
    iter: *mut Iter,
    key: *mut *const c_char,
    keylen: *mut size_t,
    val: *mut *const c_char,
    vallen: *mut size_t,
) -> c_uchar {
    match (*iter).next() {
        Some(Ok((k, v))) => {
            *key = leak_buf(k.to_vec(), keylen);
            *val = leak_buf(v.to_vec(), vallen);
            1
        }
        // TODO proper error propagation
        Some(Err(e)) => panic!("{:?}", e),
        None => 0,
    }
}
<commit_msg>Revert "Avoid round-trip Config raw pointer"<commit_after>use sled;

use std::ffi::CString;
use std::mem;
use std::ptr;
use std::slice;

use libc::*;

use sled::{Config, Db, Iter};

fn leak_buf(v: Vec<u8>, vallen: *mut size_t) -> *mut c_char {
    unsafe {
        *vallen = v.len();
    }
    let mut bsv = v.into_boxed_slice();
    let val = bsv.as_mut_ptr() as *mut _;
    mem::forget(bsv);
    val
}

/// Create a new configuration.
#[no_mangle]
pub unsafe extern "C" fn sled_create_config() -> *mut Config {
    Box::into_raw(Box::new(Config::new()))
}

/// Destroy a configuration.
#[no_mangle]
pub unsafe extern "C" fn sled_free_config(config: *mut Config) {
    drop(Box::from_raw(config));
}

/// Set the configured file path. The caller is responsible for freeing the path
/// string after calling this (it is copied in this function).
#[no_mangle]
pub unsafe extern "C" fn sled_config_set_path(
    config: *mut Config,
    path: *const c_char,
) -> *mut Config {
    let c_str = CString::from_raw(path as *mut _);
    let value = c_str.into_string().unwrap();

    let config = Box::from_raw(config);
    Box::into_raw(Box::from(config.path(value)))
}

/// Configure read-only mode.
#[no_mangle]
pub unsafe extern "C" fn sled_config_read_only(
    config: *mut Config,
    read_only: c_uchar,
) -> *mut Config {
    let config = Box::from_raw(config);
    Box::into_raw(Box::from(config.read_only(read_only == 1)))
}

/// Set the configured cache capacity in bytes.
#[no_mangle]
pub unsafe extern "C" fn sled_config_set_cache_capacity(
    config: *mut Config,
    capacity: size_t,
) -> *mut Config {
    let config = Box::from_raw(config);
    Box::into_raw(Box::from(config.cache_capacity(capacity as u64)))
}

/// Configure the use of the zstd compression library.
#[no_mangle]
pub unsafe extern "C" fn sled_config_use_compression(
    config: *mut Config,
    use_compression: c_uchar,
) -> *mut Config {
    let config = Box::from_raw(config);
    Box::into_raw(Box::from(config.use_compression(use_compression == 1)))
}

/// Set the configured IO buffer flush interval in milliseconds.
#[no_mangle]
pub unsafe extern "C" fn sled_config_flush_every_ms(
    config: *mut Config,
    flush_every: c_int,
) -> *mut Config {
    let val = if flush_every < 0 { None } else { Some(flush_every as u64) };
    let config = Box::from_raw(config);
    Box::into_raw(Box::from(config.flush_every_ms(val)))
}

/// Open a sled lock-free log-structured tree. Consumes the passed-in config.
#[no_mangle]
pub unsafe extern "C" fn sled_open_db(config: *mut Config) -> *mut Db {
    let config = Box::from_raw(config);
    Box::into_raw(Box::new(config.open().unwrap()))
}

/// Close a sled lock-free log-structured tree.
#[no_mangle]
pub unsafe extern "C" fn sled_close(db: *mut Db) {
    drop(Box::from_raw(db));
}

/// Free a buffer originally allocated by sled.
#[no_mangle]
pub unsafe extern "C" fn sled_free_buf(buf: *mut c_char, sz: size_t) {
    drop(Vec::from_raw_parts(buf, sz, sz));
}

/// Free an iterator.
#[no_mangle]
pub unsafe extern "C" fn sled_free_iter(iter: *mut Iter) {
    drop(Box::from_raw(iter));
}

/// Set a key to a value.
#[no_mangle]
pub unsafe extern "C" fn sled_set(
    db: *mut Db,
    key: *const c_uchar,
    keylen: size_t,
    val: *const c_uchar,
    vallen: size_t,
) {
    let k = slice::from_raw_parts(key, keylen).to_vec();
    let v = slice::from_raw_parts(val, vallen).to_vec();
    (*db).insert(k, v).unwrap();
}

/// Get the value of a key.
/// Caller is responsible for freeing the returned value with `sled_free_buf` if
/// it's non-null.
#[no_mangle]
pub unsafe extern "C" fn sled_get(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
    vallen: *mut size_t,
) -> *mut c_char {
    let k = slice::from_raw_parts(key as *const u8, keylen);
    let res = (*db).get(k);
    match res {
        Ok(Some(v)) => leak_buf(v.to_vec(), vallen),
        Ok(None) => ptr::null_mut(),
        // TODO proper error propagation
        Err(e) => panic!("{:?}", e),
    }
}

/// Delete the value of a key.
#[no_mangle]
pub unsafe extern "C" fn sled_del(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
) {
    let k = slice::from_raw_parts(key as *const u8, keylen);
    (*db).remove(k).unwrap();
}

/// Compare and swap.
/// Returns 1 if successful, 0 if unsuccessful.
/// Otherwise sets `actual_val` and `actual_vallen` to the current value,
/// which must be freed using `sled_free_buf` by the caller if non-null.
/// `actual_val` will be null and `actual_vallen` 0 if the current value is not
/// set.
#[no_mangle]
pub unsafe extern "C" fn sled_compare_and_swap(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
    old_val: *const c_uchar,
    old_vallen: size_t,
    new_val: *const c_uchar,
    new_vallen: size_t,
    actual_val: *mut *const c_uchar,
    actual_vallen: *mut size_t,
) -> c_uchar {
    let k = slice::from_raw_parts(key as *const u8, keylen).to_vec();

    let old = if old_vallen == 0 {
        None
    } else {
        let old_slice = slice::from_raw_parts(old_val as *const u8, old_vallen);
        let copy = old_slice.to_vec();
        Some(copy)
    };

    let new = if new_vallen == 0 {
        None
    } else {
        let new_slice = slice::from_raw_parts(new_val as *const u8, new_vallen);
        let copy = new_slice.to_vec();
        Some(copy)
    };

    let res = (*db).compare_and_swap(k, old, new);

    match res {
        Ok(Ok(())) => 1,
        Ok(Err(sled::CompareAndSwapError { current: None, .. })) => {
            *actual_vallen = 0;
            0
        }
        Ok(Err(sled::CompareAndSwapError { current: Some(v), .. })) => {
            *actual_val = leak_buf(v.to_vec(), actual_vallen) as *const u8;
            0
        }
        // TODO proper error propagation
        Err(e) => panic!("{:?}", e),
    }
}

/// Iterate over tuples which have specified key prefix.
/// Caller is responsible for freeing the returned iterator with
/// `sled_free_iter`.
#[no_mangle]
pub unsafe extern "C" fn sled_scan_prefix(
    db: *mut Db,
    key: *const c_char,
    keylen: size_t,
) -> *mut Iter {
    let k = slice::from_raw_parts(key as *const u8, keylen);
    Box::into_raw(Box::new((*db).scan_prefix(k)))
}

/// Get they next kv pair from an iterator.
/// Caller is responsible for freeing the key and value with `sled_free_buf`.
/// Returns 0 when exhausted.
#[no_mangle]
pub unsafe extern "C" fn sled_iter_next(
    iter: *mut Iter,
    key: *mut *const c_char,
    keylen: *mut size_t,
    val: *mut *const c_char,
    vallen: *mut size_t,
) -> c_uchar {
    match (*iter).next() {
        Some(Ok((k, v))) => {
            *key = leak_buf(k.to_vec(), keylen);
            *val = leak_buf(v.to_vec(), vallen);
            1
        }
        // TODO proper error propagation
        Some(Err(e)) => panic!("{:?}", e),
        None => 0,
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops::Index;
use std::slice::Iter;
use std::vec::Vec;

use itertools::Itertools;

use types::*;

pub type ColumnId = usize;

#[derive(Clone, PartialEq, Debug)]
pub struct Field {
  pub name: String,
  pub decl: FieldDecl
}

impl Field {
  pub fn new<T: AsRef<str>>(name: T, decl: FieldDecl) -> Field {
    Field {
      name: name.as_ref().to_string(),
      decl: decl
    }
  }

  pub fn scalar<T: AsRef<str>>(name: T, ty: Ty) -> Field {
    Field::new(name, FieldDecl::Scalar(ty))
  }

  pub fn array<T: AsRef<str>>(name: T, decl: FieldDecl) -> Field {
    Field::new(name, FieldDecl::Array(Box::new(decl)))
  }

  pub fn map<T: AsRef<str>>(name: T, key_ty: FieldDecl, val_ty: FieldDecl) -> Field {
    Field::new(name, FieldDecl::Map(Box::new(key_ty), Box::new(val_ty)))
  }

  pub fn record<T: AsRef<str>>(name: T, r: Record) -> Field {
    Field::new(name, FieldDecl::Record(r))
  }

  pub fn record_from_vec<T: AsRef<str>>(name: T, fields: Vec<Field>) -> Field {
    Field {
      name: name.as_ref().to_string(),
      decl: FieldDecl::Record(Record::new(fields))
    }
  }

  pub fn name(&self) -> &str {
    &self.name
  }
}

impl fmt::Display for Field {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", display_field(self))
  }
}

fn display_field(f: &Field) -> String {
  format!("{} {}", f.name, f.decl)
}

#[derive(Clone, PartialEq, Debug)]
pub enum FieldDecl {
  Scalar (Ty),
  Record (Record),
  Array  (Box<FieldDecl>),
  Map    (Box<FieldDecl>, Box<FieldDecl>)
}

impl FieldDecl {
  pub fn scalar(ty: Ty) -> FieldDecl {
    FieldDecl::Scalar(ty)
  }

  pub fn record_from_fields(fields: Vec<Field>) -> FieldDecl {
    FieldDecl::Record(Record::new(fields))
  }
}

impl fmt::Display for FieldDecl {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", display_field_decl(self))
  }
}

fn display_field_decl(decl: &FieldDecl) -> String {
  match *decl {
    FieldDecl::Scalar(ref ty)         => ty.name().to_owned(),
    FieldDecl::Record(ref r)          => format!("record ({})", r),
    FieldDecl::Array (ref vt)         => format!("array<{}>", vt),
    FieldDecl::Map   (ref kt, ref vt) => format!("map<{},{}>", kt, vt)
  }
}

#[derive(Clone, PartialEq, Debug)]
pub struct Record {
  fields: Vec<Field>
}

impl Record {
  pub fn new(fields: Vec<Field>) -> Record {
    Record {fields: fields}
  }

  pub fn size(&self) -> usize {
    self.fields.len()
  }

  pub fn find_id(&self, name: &str) -> Option<ColumnId> {
    self.fields.iter().position(|f| f.name == name)
  }

  pub fn find_by_name(&self, name : &str) -> Option<&Field> {
    self.fields.iter().filter(|&f| f.name == name).next()
  }

  pub fn iter(&self) -> Iter<Field> {
    self.fields.iter()
  }
}

impl Index<ColumnId> for Record {
  type Output = Field;
  fn index<'a>(&'a self, id: ColumnId) -> &'a Field {
    debug_assert!(id < self.fields.len(), "Field index is out of range");
    &self.fields[id]
  }
}

impl fmt::Display for Record {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", display_fields(&self.fields))
  }
}

#[inline]
fn display_fields(fields: &Vec<Field>) -> String {
  fields.iter().map(|f| display_field(f)).join(", ")
}

#[allow(dead_code)]
fn create_test_schema() -> Record {
	Record::new(vec![
    Field::scalar("col1", *INT4_TY),
    Field::record_from_vec("col2", vec![
        Field::scalar("col3", *INT4_TY),
        Field::scalar("col4", *INT4_TY)
      ]
    ),
    Field::record_from_vec("col5", vec![
        Field::array("col6", FieldDecl::scalar(*INT8_TY)),
        Field::array("col7", FieldDecl::scalar(*INT8_TY)),
      ]
    ),
    Field::map("col8", FieldDecl::scalar(*INT4_TY), FieldDecl::record_from_fields(
      vec![
        Field::scalar("col9",  *TEXT_TY),
        Field::scalar("col10", *TEXT_TY),
      ])
    )
  ])
}

#[test]
fn test_schema_creation() {
  let schema = create_test_schema();
  assert_eq!(
    "col1 int4, col2 record (col3 int4, col4 int4), col5 record (col6 array<int8>, col7 array<int8>), col8 map<int4,record (col9 text, col10 text)>".to_string(),
    format!("{}", schema));
}
<commit_msg>Rename FieldDecl::record_from_fields to record_from_vec.<commit_after>use std::fmt;
use std::ops::Index;
use std::slice::Iter;
use std::vec::Vec;

use itertools::Itertools;

use types::*;

pub type ColumnId = usize;

#[derive(Clone, PartialEq, Debug)]
pub struct Field {
  pub name: String,
  pub decl: FieldDecl
}

impl Field {
  pub fn new<T: AsRef<str>>(name: T, decl: FieldDecl) -> Field {
    Field {
      name: name.as_ref().to_string(),
      decl: decl
    }
  }

  pub fn scalar<T: AsRef<str>>(name: T, ty: Ty) -> Field {
    Field::new(name, FieldDecl::Scalar(ty))
  }

  pub fn array<T: AsRef<str>>(name: T, decl: FieldDecl) -> Field {
    Field::new(name, FieldDecl::Array(Box::new(decl)))
  }

  pub fn map<T: AsRef<str>>(name: T, key_ty: FieldDecl, val_ty: FieldDecl) -> Field {
    Field::new(name, FieldDecl::Map(Box::new(key_ty), Box::new(val_ty)))
  }

  pub fn record<T: AsRef<str>>(name: T, r: Record) -> Field {
    Field::new(name, FieldDecl::Record(r))
  }

  pub fn record_from_vec<T: AsRef<str>>(name: T, fields: Vec<Field>) -> Field {
    Field {
      name: name.as_ref().to_string(),
      decl: FieldDecl::Record(Record::new(fields))
    }
  }

  pub fn name(&self) -> &str {
    &self.name
  }
}

impl fmt::Display for Field {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", display_field(self))
  }
}

fn display_field(f: &Field) -> String {
  format!("{} {}", f.name, f.decl)
}

#[derive(Clone, PartialEq, Debug)]
pub enum FieldDecl {
  Scalar (Ty),
  Record (Record),
  Array  (Box<FieldDecl>),
  Map    (Box<FieldDecl>, Box<FieldDecl>)
}

impl FieldDecl {
  pub fn scalar(ty: Ty) -> FieldDecl {
    FieldDecl::Scalar(ty)
  }

  pub fn record_from_vec(fields: Vec<Field>) -> FieldDecl {
    FieldDecl::Record(Record::new(fields))
  }
}

impl fmt::Display for FieldDecl {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", display_field_decl(self))
  }
}

fn display_field_decl(decl: &FieldDecl) -> String {
  match *decl {
    FieldDecl::Scalar(ref ty)         => ty.name().to_owned(),
    FieldDecl::Record(ref r)          => format!("record ({})", r),
    FieldDecl::Array (ref vt)         => format!("array<{}>", vt),
    FieldDecl::Map   (ref kt, ref vt) => format!("map<{},{}>", kt, vt)
  }
}

#[derive(Clone, PartialEq, Debug)]
pub struct Record {
  fields: Vec<Field>
}

impl Record {
  pub fn new(fields: Vec<Field>) -> Record {
    Record {fields: fields}
  }

  pub fn size(&self) -> usize {
    self.fields.len()
  }

  pub fn find_id(&self, name: &str) -> Option<ColumnId> {
    self.fields.iter().position(|f| f.name == name)
  }

  pub fn find_by_name(&self, name : &str) -> Option<&Field> {
    self.fields.iter().filter(|&f| f.name == name).next()
  }

  pub fn iter(&self) -> Iter<Field> {
    self.fields.iter()
  }
}

impl Index<ColumnId> for Record {
  type Output = Field;
  fn index<'a>(&'a self, id: ColumnId) -> &'a Field {
    debug_assert!(id < self.fields.len(), "Field index is out of range");
    &self.fields[id]
  }
}

impl fmt::Display for Record {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", display_fields(&self.fields))
  }
}

#[inline]
fn display_fields(fields: &Vec<Field>) -> String {
  fields.iter().map(|f| display_field(f)).join(", ")
}

#[allow(dead_code)]
fn create_test_schema() -> Record {
	Record::new(vec![
    Field::scalar("col1", *INT4_TY),
    Field::record_from_vec("col2", vec![
        Field::scalar("col3", *INT4_TY),
        Field::scalar("col4", *INT4_TY)
      ]
    ),
    Field::record_from_vec("col5", vec![
        Field::array("col6", FieldDecl::scalar(*INT8_TY)),
        Field::array("col7", FieldDecl::scalar(*INT8_TY)),
      ]
    ),
    Field::map("col8", FieldDecl::scalar(*INT4_TY), FieldDecl::record_from_vec(
      vec![
        Field::scalar("col9",  *TEXT_TY),
        Field::scalar("col10", *TEXT_TY),
      ])
    )
  ])
}

#[test]
fn test_schema_creation() {
  let schema = create_test_schema();
  assert_eq!(
    "col1 int4, col2 record (col3 int4, col4 int4), col5 record (col6 array<int8>, col7 array<int8>), col8 map<int4,record (col9 text, col10 text)>".to_string(),
    format!("{}", schema));
}
<|endoftext|>


<commit_before>#![feature(os, io, path)]

use std::os;
use std::old_io::fs::PathExtensions;

#[cfg(target_os="macos")]
fn main() {
    /*
    let cef_dir = os::getenv("CEF_PATH")
        .expect("CEF_PATH needs to point to the directory containing the CEF DLL.");

    let cef_dir = Path::new(cef_dir);

    let cef_lib = "Chromium Embedded Framework.framework".to_owned();

    let cef_path = cef_dir.join(cef_lib.clone());
    if !cef_path.exists() {
        panic!("Unable to find {} in {}", cef_lib, cef_dir.as_str().unwrap());
    }
    println!("cargo:rustc-flags= -L {}",
             cef_dir.as_str().unwrap());*/
}

#[cfg(target_os="linux")]
fn main() {
    let cef_dir = os::getenv("CEF_PATH")
        .expect("CEF_PATH needs to point to the directory containing the CEF DLL.");

    let cef_dir = Path::new(cef_dir);

    let cef_lib = os::dll_filename("cef");

    let cef_path = cef_dir.join(cef_lib.clone());
    if !cef_path.exists() {
        panic!("Unable to find {} in {}", cef_lib, cef_dir.as_str().unwrap());
    }
    println!("cargo:rustc-flags=-l cef -L {}", cef_dir.as_str().unwrap());
}

#[cfg(target_os="windows")]
fn main() {
    let cef_dir = os::getenv("CEF_PATH")
        .expect("CEF_PATH needs to point to the directory containing the CEF DLL.");

    let cef_dir = Path::new(cef_dir);

    let cef_lib = os::dll_filename("libcef");

    let cef_path = cef_dir.join(cef_lib.clone());
    if !cef_path.exists() {
        panic!("Unable to find {} in {}", cef_lib, cef_dir.as_str().unwrap());
    }
    println!("cargo:rustc-flags=-l libcef -L {}", cef_dir.as_str().unwrap());
}
<commit_msg>Updated build script to support cross-compilation.<commit_after>#![feature(os, io, path)]

use std::os;
use std::old_io::fs::PathExtensions;

enum Platform {
    Windows,
    Mac,
    Linux
}

fn get_platform() -> Platform {
    match os::getenv("TARGET").unwrap().split('-').nth(2).unwrap() {
        "win32" | "windows" => Platform::Windows,
        "darwin" => Platform::Mac,
        "linux" => Platform::Linux,
        other => panic!("Sorry, platform \"{}\" is not supported by cef-sys.", other)
    }
}

fn main() {
    let dll_name = match get_platform() {
        Platform::Mac => return, // CEF_PATH is not necessarily needed for Mac
        Platform::Windows => "libcef",
        Platform::Linux => "cef"
    };
    let dll_file_name = os::dll_filename(dll_name);
    let cef_dir = Path::new(os::getenv("CEF_PATH")
        .expect("CEF_PATH needs to point to the directory containing the CEF DLL."));
    let cef_path = cef_dir.join(dll_file_name.clone());
    if !cef_path.exists() {
        panic!("Unable to find {} in {}", dll_file_name, cef_dir.as_str().unwrap());
    }
    println!("cargo:rustc-flags=-l {} -L {}", dll_name, cef_dir.as_str().unwrap());
}

/*
fn main() {

    let cef_dir = os::getenv("CEF_PATH")
        .expect("CEF_PATH needs to point to the directory containing the CEF DLL.");

    let cef_dir = Path::new(cef_dir);

    let cef_lib = "Chromium Embedded Framework.framework".to_owned();

    let cef_path = cef_dir.join(cef_lib.clone());
    if !cef_path.exists() {
        panic!("Unable to find {} in {}", cef_lib, cef_dir.as_str().unwrap());
    }
    println!("cargo:rustc-flags= -L {}",
             cef_dir.as_str().unwrap());
}
*/
<|endoftext|>