<commit_before>pub mod error_handling;

use libc::c_char;
use llvm_sys::core::LLVMDisposeMessage;
use llvm_sys::support::LLVMLoadLibraryPermanently;

use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter};
use std::ffi::{CString, CStr};
use std::ops::Deref;

/// An owned LLVM String. Also known as a LLVM Message
#[derive(Eq)]
pub struct LLVMString {
    pub(crate) ptr: *const c_char,
}

impl LLVMString {
    pub(crate) fn new(ptr: *const c_char) -> Self {
        LLVMString {
            ptr,
        }
    }

    /// This is a convenience method for creating a Rust `String`,
    /// however; it *will* reallocate. `LLVMString` should be used
    /// as much as possible to save memory since it is allocated by
    /// LLVM. It's essentially a `CString` with a custom LLVM
    /// deallocator
    pub fn to_string(&self) -> String {
        (*self).to_string_lossy().into_owned()
    }
}

impl Deref for LLVMString {
    type Target = CStr;

    fn deref(&self) -> &Self::Target {
        unsafe {
            CStr::from_ptr(self.ptr)
        }
    }
}

impl Debug for LLVMString {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:?}", *self)
    }
}

impl Display for LLVMString {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", *self)
    }
}

impl PartialEq for LLVMString {
    fn eq(&self, other: &LLVMString) -> bool {
        **self == **other
    }
}

impl Error for LLVMString {
    fn description(&self) -> &str {
        self.to_str().expect("Could not convert LLVMString to str (likely invalid unicode)")
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl Drop for LLVMString {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeMessage(self.ptr as *mut _);
        }
    }
}

// Similar to Cow; however does not provide ability to clone
// since memory is allocated by LLVM. Could use a better name
// too. This is meant to be an internal wrapper only. Maybe
// belongs in a private utils module.
#[derive(Eq)]
pub(crate) enum LLVMStringOrRaw {
    Owned(LLVMString),
    Borrowed(*const c_char),
}

impl LLVMStringOrRaw {
    pub fn as_str(&self) -> &CStr {
        match self {
            LLVMStringOrRaw::Owned(llvm_string) => llvm_string.deref(),
            LLVMStringOrRaw::Borrowed(ptr) => unsafe {
                CStr::from_ptr(*ptr)
            },
        }
    }
}

impl PartialEq for LLVMStringOrRaw {
    fn eq(&self, other: &LLVMStringOrRaw) -> bool {
        self.as_str() == other.as_str()
    }
}

// REVIEW: Not sure how safe this is. What happens when you make an llvm call after
// shutdown_llvm has been called?
pub fn shutdown_llvm() {
    use llvm_sys::core::LLVMShutdown;

    unsafe {
        LLVMShutdown()
    }
}

pub fn load_library_permanently(filename: &str) -> bool {
    let filename = CString::new(filename).expect("Conversion to CString failed unexpectedly");

    unsafe {
        LLVMLoadLibraryPermanently(filename.as_ptr()) == 1
    }
}

pub fn is_multithreaded() -> bool {
    use llvm_sys::core::LLVMIsMultithreaded;

    unsafe {
        LLVMIsMultithreaded() == 1
    }
}
<commit_msg>Fixed an issue with LLVMString where Debug/Display would infinitely recurse<commit_after>pub mod error_handling;

use libc::c_char;
use llvm_sys::core::LLVMDisposeMessage;
use llvm_sys::support::LLVMLoadLibraryPermanently;

use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter};
use std::ffi::{CString, CStr};
use std::ops::Deref;

/// An owned LLVM String. Also known as a LLVM Message
#[derive(Eq)]
pub struct LLVMString {
    pub(crate) ptr: *const c_char,
}

impl LLVMString {
    pub(crate) fn new(ptr: *const c_char) -> Self {
        LLVMString {
            ptr,
        }
    }

    /// This is a convenience method for creating a Rust `String`,
    /// however; it *will* reallocate. `LLVMString` should be used
    /// as much as possible to save memory since it is allocated by
    /// LLVM. It's essentially a `CString` with a custom LLVM
    /// deallocator
    pub fn to_string(&self) -> String {
        (*self).to_string_lossy().into_owned()
    }
}

impl Deref for LLVMString {
    type Target = CStr;

    fn deref(&self) -> &Self::Target {
        unsafe {
            CStr::from_ptr(self.ptr)
        }
    }
}

impl Debug for LLVMString {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:?}", self.deref())
    }
}

impl Display for LLVMString {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:?}", self.deref())
    }
}

impl PartialEq for LLVMString {
    fn eq(&self, other: &LLVMString) -> bool {
        **self == **other
    }
}

impl Error for LLVMString {
    fn description(&self) -> &str {
        self.to_str().expect("Could not convert LLVMString to str (likely invalid unicode)")
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl Drop for LLVMString {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeMessage(self.ptr as *mut _);
        }
    }
}

// Similar to Cow; however does not provide ability to clone
// since memory is allocated by LLVM. Could use a better name
// too. This is meant to be an internal wrapper only. Maybe
// belongs in a private utils module.
#[derive(Eq)]
pub(crate) enum LLVMStringOrRaw {
    Owned(LLVMString),
    Borrowed(*const c_char),
}

impl LLVMStringOrRaw {
    pub fn as_str(&self) -> &CStr {
        match self {
            LLVMStringOrRaw::Owned(llvm_string) => llvm_string.deref(),
            LLVMStringOrRaw::Borrowed(ptr) => unsafe {
                CStr::from_ptr(*ptr)
            },
        }
    }
}

impl PartialEq for LLVMStringOrRaw {
    fn eq(&self, other: &LLVMStringOrRaw) -> bool {
        self.as_str() == other.as_str()
    }
}

// REVIEW: Not sure how safe this is. What happens when you make an llvm call after
// shutdown_llvm has been called?
pub fn shutdown_llvm() {
    use llvm_sys::core::LLVMShutdown;

    unsafe {
        LLVMShutdown()
    }
}

pub fn load_library_permanently(filename: &str) -> bool {
    let filename = CString::new(filename).expect("Conversion to CString failed unexpectedly");

    unsafe {
        LLVMLoadLibraryPermanently(filename.as_ptr()) == 1
    }
}

pub fn is_multithreaded() -> bool {
    use llvm_sys::core::LLVMIsMultithreaded;

    unsafe {
        LLVMIsMultithreaded() == 1
    }
}
<|endoftext|>


<commit_before>extern mod std;

use std::*;
use io::{ReaderUtil,WriterUtil};

enum Result {
  Nil,
  Int(int),
  Data(~str),
  List(~[Result]),
  Error(~str),
  Status(~str)
}

priv fn parse_data(len: uint, sb: net::tcp::TcpSocketBuf) -> Result {
  let res =
    if (len > 0) {
      let bytes = sb.read_bytes(len as uint);
      assert bytes.len() == len;
      Data(str::from_bytes(bytes))
    } else {
      Data(~"")
    };
  assert sb.read_char() == '\r';
  assert sb.read_char() == '\n';
  return res;
}

fn parse_list(len: uint, sb: net::tcp::TcpSocketBuf) -> Result {
  let mut list: ~[Result] = ~[];
  for len.times {
    let line = sb.read_line();
    assert line.len() >= 1;
    let c = line.char_at(0);
    let rest = line.slice(1, line.len() - 1);
    let v =
      match c {
	'$' =>
	  match int::from_str(rest) {
	    None => fail,
	    Some(-1) => Nil,
	    Some(len) if len >= 0 => parse_data(len as uint, sb),
	    Some(_) => fail
	  },
	_ => fail
      };
    list.push(v);
  }
  return List(list);
}

// XXX: use read_char, then read_line!
fn parse_response(sb: net::tcp::TcpSocketBuf) -> Result {
  let line = sb.read_line();
  assert line.len() >= 1;

  let c = line.char_at(0);
  let rest = line.slice(1, line.len() - 1);

  match c {
    '$' =>
      match int::from_str(rest) {
        None => fail,
        Some(-1) => Nil,
        Some(len) if len >= 0 => parse_data(len as uint, sb),
        Some(_) => fail
      },
    '*' =>
      match int::from_str(rest) {
        None => fail,
        Some(-1) => Nil,
        Some(0) => List(~[]),
        Some(len) if len >= 0 => parse_list(len as uint, sb),
        Some(_) => fail
      },
    '+' => Status(rest),
    '-' => Error(rest),
    ':' => match int::from_str(rest) {
             None => fail,
             Some(i) => Int(i)
           },
    _   => fail
  }
}

fn cmd_to_str(cmd: ~[~str]) -> ~str {
  let mut res = ~"*";
  str::push_str(&mut res, cmd.len().to_str());
  str::push_str(&mut res, "\r\n");
  for cmd.each |s| {
    str::push_str(&mut res, str::concat(~[~"$", s.len().to_str(), ~"\r\n", *s, ~"\r\n"]));
  }
  res
}

fn query(cmd: ~[~str], sb: net::tcp::TcpSocketBuf) -> Result {
  let cmd = cmd_to_str(cmd);
  io::println(cmd);
  sb.write_str(cmd);
  let res = parse_response(sb);
  io::println(fmt!("%?", res));
  res
}

fn main() {
  let server_ip_addr = net::ip::v4::parse_addr("127.0.0.1");
  let server_port = 6379;
  let iotask = uv::global_loop::get();
  let connect_result = net::tcp::connect(server_ip_addr, server_port, iotask);
  let sock = result::unwrap(connect_result);
  let sb = net::tcp::socket_buf(sock);

  query(~[~"SET", ~"abc", ~"XXX"], sb);
  query(~[~"SET", ~"def", ~"123"], sb);
  query(~[~"GET", ~"abc"], sb);
  query(~[~"MGET", ~"abc", ~"def", ~"non"], sb);
}
<commit_msg>Refactor code<commit_after>extern mod std;

use std::*;
use io::{ReaderUtil,WriterUtil};

enum Result {
  Nil,
  Int(int),
  Data(~str),
  List(~[Result]),
  Error(~str),
  Status(~str)
}

priv fn parse_data(len: uint, sb: net::tcp::TcpSocketBuf) -> Result {
  let res =
    if (len > 0) {
      let bytes = sb.read_bytes(len as uint);
      assert bytes.len() == len;
      Data(str::from_bytes(bytes))
    } else {
      Data(~"")
    };
  assert sb.read_char() == '\r';
  assert sb.read_char() == '\n';
  return res;
}

fn parse_list(len: uint, sb: net::tcp::TcpSocketBuf) -> Result {
  let mut list: ~[Result] = ~[];
  for len.times {
    if sb.read_char() != '$' { fail }
    list.push(parse_bulk(sb));
  }
  return List(list);
}

priv fn chop(s: ~str) -> ~str {
  s.slice(0, s.len() - 1)
}

priv fn parse_bulk(sb: net::tcp::TcpSocketBuf) -> Result {
  match int::from_str(chop(sb.read_line())) {
    None => fail,
    Some(-1) => Nil,
    Some(len) if len >= 0 => parse_data(len as uint, sb),
    Some(_) => fail
  }
}

priv fn parse_multi(sb: net::tcp::TcpSocketBuf) -> Result {
  match int::from_str(chop(sb.read_line())) {
    None => fail,
    Some(-1) => Nil,
    Some(0) => List(~[]),
    Some(len) if len >= 0 => parse_list(len as uint, sb),
    Some(_) => fail
  }
}

fn parse_response(sb: net::tcp::TcpSocketBuf) -> Result {
  match sb.read_char() {
    '$' => parse_bulk(sb),
    '*' => parse_multi(sb),
    '+' => Status(chop(sb.read_line())),
    '-' => Error(chop(sb.read_line())),
    ':' => match int::from_str(chop(sb.read_line())) {
             None => fail,
             Some(i) => Int(i)
           },
    _   => fail
  }
}

fn cmd_to_str(cmd: ~[~str]) -> ~str {
  let mut res = ~"*";
  str::push_str(&mut res, cmd.len().to_str());
  str::push_str(&mut res, "\r\n");
  for cmd.each |s| {
    str::push_str(&mut res, str::concat(~[~"$", s.len().to_str(), ~"\r\n", *s, ~"\r\n"]));
  }
  res
}

fn query(cmd: ~[~str], sb: net::tcp::TcpSocketBuf) -> Result {
  let cmd = cmd_to_str(cmd);
  io::println(cmd);
  sb.write_str(cmd);
  let res = parse_response(sb);
  io::println(fmt!("%?", res));
  res
}

fn main() {
  let server_ip_addr = net::ip::v4::parse_addr("127.0.0.1");
  let server_port = 6379;
  let iotask = uv::global_loop::get();
  let connect_result = net::tcp::connect(server_ip_addr, server_port, iotask);
  let sock = result::unwrap(connect_result);
  let sb = net::tcp::socket_buf(sock);

  query(~[~"SET", ~"abc", ~"XXX"], sb);
  query(~[~"SET", ~"def", ~"123"], sb);
  query(~[~"GET", ~"abc"], sb);
  query(~[~"MGET", ~"abc", ~"def", ~"non"], sb);
}
<|endoftext|>


<commit_before>
/// Implemented by contexts that can transform.
pub trait Transform2d<'a> {
    /// Translate x and y.
    fn trans(&'a self, x: f64, y: f64) -> Self;

    /// Translate x an y in local coordinates.
    fn trans_local(&'a self, x: f64, y: f64) -> Self;

    /// Rotates degrees.
    #[inline(always)]
    fn rot_deg(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotates degrees.
    #[inline(always)]
    fn rot_deg_local(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad_local(angle * pi / 180.0)
    }

    /// Rotate radians.
    fn rot_rad(&'a self, angle: f64) -> Self;

    /// Rotate radians in local coordinates.
    fn rot_rad_local(&'a self, angle: f64) -> Self;

    /// Scale.
    fn scale(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in local coordinates.
    fn scale_local(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in both directions.
    #[inline(always)]
    fn zoom(&'a self, s: f64) -> Self {
        self.scale(s, s)
    }

    /// Scales in both directions.
    #[inline(always)]
    fn zoom_local(&'a self, s: f64) -> Self {
        self.scale_local(s, s)
    }

    /// Flips vertically.
    #[inline(always)]
    fn flip_v(&'a self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips horizontally.
    #[inline(always)]
    fn flip_h(&'a self) -> Self {
        self.scale(-1.0, 0.0)
    }

    /// Shear.
    fn shear(&'a self, sx: f64, sy: f64) -> Self;

    /// Shears in local coordinates.
    fn shear_local(&'a self, sx: f64, sy: f64) -> Self;
}
<commit_msg>Added `flip_v_local` to `Transform2d`<commit_after>
/// Implemented by contexts that can transform.
pub trait Transform2d<'a> {
    /// Translate x and y.
    fn trans(&'a self, x: f64, y: f64) -> Self;

    /// Translate x an y in local coordinates.
    fn trans_local(&'a self, x: f64, y: f64) -> Self;

    /// Rotates degrees.
    #[inline(always)]
    fn rot_deg(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotates degrees.
    #[inline(always)]
    fn rot_deg_local(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad_local(angle * pi / 180.0)
    }

    /// Rotate radians.
    fn rot_rad(&'a self, angle: f64) -> Self;

    /// Rotate radians in local coordinates.
    fn rot_rad_local(&'a self, angle: f64) -> Self;

    /// Scale.
    fn scale(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in local coordinates.
    fn scale_local(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in both directions.
    #[inline(always)]
    fn zoom(&'a self, s: f64) -> Self {
        self.scale(s, s)
    }

    /// Scales in both directions.
    #[inline(always)]
    fn zoom_local(&'a self, s: f64) -> Self {
        self.scale_local(s, s)
    }

    /// Flips vertically.
    #[inline(always)]
    fn flip_v(&'a self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips vertically in local coordinates.
    #[inline(always)]
    fn flip_v_local(&'a self) -> Self {
        self.scale_local(1.0, -1.0)
    }

    /// Flips horizontally.
    #[inline(always)]
    fn flip_h(&'a self) -> Self {
        self.scale(-1.0, 0.0)
    }

    /// Shear.
    fn shear(&'a self, sx: f64, sy: f64) -> Self;

    /// Shears in local coordinates.
    fn shear_local(&'a self, sx: f64, sy: f64) -> Self;
}
<|endoftext|>


<commit_before>//! The `join` macro.

/// Polls multiple futures simultaneously, returning a tuple
/// of all results once complete.
///
/// While `join!(a, b)` is similar to `(await!(a), await!(b))`,
/// `join!` polls both futures concurrently and therefore is more efficent.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{join, future};
///
/// let a = future::ready(1);
/// let b = future::ready(2);
///
/// assert_eq!(join!(a, b), (1, 2));
/// # });
/// ```
#[macro_export]
macro_rules! join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*
        loop {
            let mut all_done = true;
            $(
                if $crate::poll!($fut.reborrow()).is_pending() {
                    all_done = false;
                }
            )*
            if all_done {
                break;
            } else {
                $crate::pending!();
            }
        }

        ($(
            $fut.reborrow().take_output().unwrap(),
        )*)
    } }
}

/// Polls multiple futures simultaneously, resolving to a [`Result`] containing
/// either a tuple of the successful outputs or an error.
///
/// `try_join!` is similar to [`join!`], but completes immediately if any of
/// the futures return an error.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// When used on multiple futures that return `Ok`, `try_join!` will return
/// `Ok` of a tuple of the values:
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Ok::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Ok((1, 2)));
/// # });
/// ```
///
/// If one of the futures resolves to an error, `try_join!` will return
/// that error:
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Err::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Err(2));
/// # });
/// ```
#[macro_export]
macro_rules! try_join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*
        let res: $crate::core_reexport::result::Result<(), _> = loop {
            let mut all_done = true;
            $(
                if $crate::poll!($fut.reborrow()).is_pending() {
                    all_done = false;
                } else if $fut.reborrow().output_mut().unwrap().is_err() {
                    // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce
                    // a `T: Debug` bound.
                    break $crate::core_reexport::result::Result::Err(
                        $fut.reborrow().take_output().unwrap().err().unwrap()
                    );
                }
            )*
            if all_done {
                break $crate::core_reexport::result::Result::Ok(());
            } else {
                $crate::pending!();
            }
        };

        res.map(|()| ($(
            // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce
            // an `E: Debug` bound.
            $fut.reborrow().take_output().unwrap().ok().unwrap(),
        )*))
    } }
}
<commit_msg>Use poll_fn in join! implementation<commit_after>//! The `join` macro.

/// Polls multiple futures simultaneously, returning a tuple
/// of all results once complete.
///
/// While `join!(a, b)` is similar to `(await!(a), await!(b))`,
/// `join!` polls both futures concurrently and therefore is more efficent.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{join, future};
///
/// let a = future::ready(1);
/// let b = future::ready(2);
///
/// assert_eq!(join!(a, b), (1, 2));
/// # });
/// ```
#[macro_export]
macro_rules! join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*
        await!($crate::future::poll_fn(|cx| {
            let mut all_done = true;
            $(
                if $crate::future::Future::poll($fut.reborrow(), cx).is_pending() {
                    all_done = false;
                }
            )*
            if all_done {
                $crate::core_reexport::task::Poll::Ready(())
            } else {
                $crate::core_reexport::task::Poll::Pending
            }
        }));

        ($(
            $fut.reborrow().take_output().unwrap(),
        )*)
    } }
}

/// Polls multiple futures simultaneously, resolving to a [`Result`] containing
/// either a tuple of the successful outputs or an error.
///
/// `try_join!` is similar to [`join!`], but completes immediately if any of
/// the futures return an error.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// When used on multiple futures that return `Ok`, `try_join!` will return
/// `Ok` of a tuple of the values:
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Ok::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Ok((1, 2)));
/// # });
/// ```
///
/// If one of the futures resolves to an error, `try_join!` will return
/// that error:
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Err::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Err(2));
/// # });
/// ```
#[macro_export]
macro_rules! try_join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*

        let res: $crate::core_reexport::result::Result<(), _> = await!($crate::future::poll_fn(|cx| {
            let mut all_done = true;
            $(
                if $crate::future::Future::poll($fut.reborrow(), cx).is_pending() {
                    all_done = false;
                } else if $fut.reborrow().output_mut().unwrap().is_err() {
                    // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce
                    // a `T: Debug` bound.
                    return $crate::core_reexport::task::Poll::Ready(
                        $crate::core_reexport::result::Result::Err(
                            $fut.reborrow().take_output().unwrap().err().unwrap()
                        )
                    );
                }
            )*
            if all_done {
                $crate::core_reexport::task::Poll::Ready(
                    $crate::core_reexport::result::Result::Ok(()))
            } else {
                $crate::core_reexport::task::Poll::Pending
            }
        }));

        res.map(|()| ($(
            // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce
            // an `E: Debug` bound.
            $fut.reborrow().take_output().unwrap().ok().unwrap(),
        )*))
    } }
}
<|endoftext|>


<commit_before>// TODO enumerate options.

use std::str::{FromStr, ParseBoolError};
use std::num::ParseIntError;
use std::error::FromError;

#[derive(Debug)]
pub struct ParseValueError(());

#[derive(Debug)]
pub struct ParseNameError(());

impl FromError<ParseNameError> for ParseValueError {
    fn from_error(_: ParseNameError) -> Self { ParseValueError(()) }
}
impl FromError<ParseIntError> for ParseValueError {
    fn from_error(_: ParseIntError) -> Self { ParseValueError(()) }
}
impl FromError<ParseBoolError> for ParseValueError {
    fn from_error(_: ParseBoolError) -> Self { ParseValueError(()) }
}
// Required since String implements FromStr with Error = ()
impl FromError<()> for ParseValueError {
    fn from_error(_: ()) -> Self { ParseValueError(()) }
}

macro_rules! declare_type {
    ($name:ident, Check) =>  { type $name = bool; };
    ($name:ident, Spin)  =>  { type $name = i64; };
    ($name:ident, Combo) =>  { type $name = u32; };
    ($name:ident, Button) => { type $name = (); };
    ($name:ident, String) => { type $name = String; };
}

macro_rules! info_impl {
    (Check() = $default:expr) => { Info::Check($default) };
    (Spin($min:expr, $max:expr) = $default:expr) => { Info::Spin($default, $min, $max) };
    (Combo($($val:expr),+) = $default:expr) => { Info::Combo($default, &[$($val,)+]) };
    (Button() = $default:expr) => { Info::Button($default) };
    (String() = $default:expr) => { Info::String($default) };
}

macro_rules! parse_value {
    ($name:expr, Combo, $value_string:expr) => {{
        let temp = $name as usize; // work around an ICE
        let combo_list: &[&'static str] = match INFO[temp] {
            Info::Combo(_, x) => &x,
            _ => unreachable!(),
        };
        combo_list.position_elem(&&*$value_string).map_or(Err(ParseValueError(())), |x| Ok(x as u32))
    }};
    ($name:expr, Button, $value_string:expr) => { Ok::<(), ParseValueError>(()) };
    ($name:expr, Spin, $value_string:expr) => {{
        let val: i64 = try!($value_string.parse());
        let temp = $name as usize; // work around an ICE
        let (min_val, max_val): (i64, i64) = match INFO[temp] {
            Info::Spin(_, x, y) => (x, y),
            _ => unreachable!(),
        };
        if val >= min_val && val <= max_val {
            Ok(val)
        } else {
            Err(ParseValueError(()))
        }
    }};
    ($name:expr, $kind:ident, $value_string:expr) => {
        $value_string.parse()
    };
}

macro_rules! options_impl {
    (($num_opt:expr) options
     $(
         $name:ident ($repr:expr) : $kind:ident ($($info:tt),*) = $default:expr,
      )+) => {

        $(declare_type!($name, $kind);)+

        #[derive(PartialEq, Eq, Clone, Debug)]
        pub enum Value {
            $($name($name),)+
        }

        #[derive(PartialEq, Eq, Copy, Clone, Debug)]
        pub enum Name {
            $($name,)+
        }

        impl FromStr for Value {
            type Err = ParseValueError;
            fn from_str(s: &str) -> Result<Self, ParseValueError> {
                // consume everything up to and including "name"
                let mut words = s.split(' ').skip_while(|&s| s != "name");
                words.next();

                let mut name_vec = Vec::<&str>::new();
                let mut value_vec = Vec::<&str>::new();

                let mut found_value = false;
                for curr_word in words {
                    if found_value {
                        value_vec.push(curr_word);
                    } else {
                        if curr_word == "value" {
                            found_value = true;
                        } else {
                            name_vec.push(curr_word);
                        }
                    }
                }

                let name_string  =  name_vec.connect(" ").trim().to_string();
                let value_string = value_vec.connect(" ").trim().to_string();

                let name: Name = try!(name_string.parse());
                Ok(match name {
                    $(
                        Name::$name => Value::$name(try!(
                                parse_value!(Name::$name, $kind, value_string))),
                    )+
                })
            }
        }

        impl FromStr for Name {
            type Err = ParseNameError;
            fn from_str(s: &str) -> Result<Self, ParseNameError> {
                match s {
                    $(
                        $repr => Ok(Name::$name),
                     )+
                    _ => Err(ParseNameError(())),
                }
            }
        }

        const INFO: [Info; $num_opt] = [$(
            info_impl!($kind($($info),*) = $default),
        )+];
    }
}

options_impl!{
    (1) options
    Hash("hash"): Spin (1, 1024) = 1,
    //TestCheck("testcheck"): Check () = false,
    //TestCombo("testcombo"): Combo ("foo", "bar", "baz") = 0,
    //TestButton("testbutton"): Button () = (),
    //TestString("teststring"): String () = "something",
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Type {
    Check,
    Spin,
    Combo,
    Button,
    String,
}

// The first fields of each variant are the default values
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Info {
    Check(bool),
    Spin(i64, i64, i64),
    Combo(u32, &'static[&'static str]),
    Button(()),
    String(&'static str),
}
<commit_msg>Make options::Info also store option::Name<commit_after>// TODO enumerate options.

use std::str::{FromStr, ParseBoolError};
use std::num::ParseIntError;
use std::error::FromError;

#[derive(Debug)]
pub struct ParseValueError(());

#[derive(Debug)]
pub struct ParseNameError(());

impl FromError<ParseNameError> for ParseValueError {
    fn from_error(_: ParseNameError) -> Self { ParseValueError(()) }
}
impl FromError<ParseIntError> for ParseValueError {
    fn from_error(_: ParseIntError) -> Self { ParseValueError(()) }
}
impl FromError<ParseBoolError> for ParseValueError {
    fn from_error(_: ParseBoolError) -> Self { ParseValueError(()) }
}
// Required since String implements FromStr with Error = ()
impl FromError<()> for ParseValueError {
    fn from_error(_: ()) -> Self { ParseValueError(()) }
}

macro_rules! declare_type {
    ($name:ident, Check) =>  { type $name = bool; };
    ($name:ident, Spin)  =>  { type $name = i64; };
    ($name:ident, Combo) =>  { type $name = u32; };
    ($name:ident, Button) => { type $name = (); };
    ($name:ident, String) => { type $name = String; };
}

macro_rules! info_impl {
    ($name:ident : Check() = $default:expr) => { Info::Check(Name::$name, $default) };
    ($name:ident : Spin($min:expr, $max:expr) = $default:expr) => { Info::Spin(Name::$name, $default, $min, $max) };
    ($name:ident : Combo($($val:expr),+) = $default:expr) => { Info::Combo(Name::$name, $default, &[$($val,)+]) };
    ($name:ident : Button() = $default:expr) => { Info::Button(Name::$name, $default) };
    ($name:ident : String() = $default:expr) => { Info::String(Name::$name, $default) };
}

macro_rules! parse_value {
    ($name:expr, Combo, $value_string:expr) => {{
        let temp = $name as usize; // work around an ICE
        let combo_list: &[&'static str] = match INFO[temp] {
            Info::Combo(_, _, x) => &x,
            _ => unreachable!(),
        };
        combo_list.position_elem(&&*$value_string).map_or(Err(ParseValueError(())), |x| Ok(x as u32))
    }};
    ($name:expr, Button, $value_string:expr) => { Ok::<(), ParseValueError>(()) };
    ($name:expr, Spin, $value_string:expr) => {{
        let val: i64 = try!($value_string.parse());
        let temp = $name as usize; // work around an ICE
        let (min_val, max_val): (i64, i64) = match INFO[temp] {
            Info::Spin(_, _, x, y) => (x, y),
            _ => unreachable!(),
        };
        if val >= min_val && val <= max_val {
            Ok(val)
        } else {
            Err(ParseValueError(()))
        }
    }};
    ($name:expr, $kind:ident, $value_string:expr) => {
        $value_string.parse()
    };
}

macro_rules! options_impl {
    // $repr is the representation as a string
    (($num_opt:expr) options
     $(
         $name:ident ($repr:expr) : $kind:ident ($($info:tt),*) = $default:expr,
      )+) => {

        $(declare_type!($name, $kind);)+

        #[derive(PartialEq, Eq, Clone, Debug)]
        pub enum Value {
            $($name($name),)+
        }

        #[derive(PartialEq, Eq, Copy, Clone, Debug)]
        pub enum Name {
            $($name,)+
        }

        const INFO: [Info; $num_opt] = [$(
            info_impl!($name: $kind($($info),*) = $default),
        )+];

        impl FromStr for Value {
            type Err = ParseValueError;
            fn from_str(s: &str) -> Result<Self, ParseValueError> {
                // consume everything up to and including "name"
                let mut words = s.split(' ').skip_while(|&s| s != "name");
                words.next();

                let mut name_vec = Vec::<&str>::new();
                let mut value_vec = Vec::<&str>::new();

                let mut found_value = false;
                for curr_word in words {
                    if found_value {
                        value_vec.push(curr_word);
                    } else {
                        if curr_word == "value" {
                            found_value = true;
                        } else {
                            name_vec.push(curr_word);
                        }
                    }
                }

                let name_string  =  name_vec.connect(" ").trim().to_string();
                let value_string = value_vec.connect(" ").trim().to_string();

                let name: Name = try!(name_string.parse());
                Ok(match name {
                    $(
                        Name::$name => Value::$name(try!(
                                parse_value!(Name::$name, $kind, value_string))),
                    )+
                })
            }
        }

        impl FromStr for Name {
            type Err = ParseNameError;
            fn from_str(s: &str) -> Result<Self, ParseNameError> {
                match s {
                    $(
                        $repr => Ok(Name::$name),
                     )+
                    _ => Err(ParseNameError(())),
                }
            }
        }
    }
}

options_impl!{
    (5) options
    Hash("hash"): Spin (1, 1024) = 1,
    TestCheck("testcheck"): Check () = false,
    TestCombo("testcombo"): Combo ("foo", "bar", "baz") = 0,
    TestButton("testbutton"): Button () = (),
    TestString("teststring"): String () = "something",
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Type {
    Check,
    Spin,
    Combo,
    Button,
    String,
}

// The second fields of each variant are the default values
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Info {
    Check(Name, bool),
    Spin(Name, i64, i64, i64),
    Combo(Name, u32, &'static[&'static str]),
    Button(Name, ()),
    String(Name, &'static str),
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS transitions and animations.

use context::SharedLayoutContext;
use flow::{self, Flow};
use gfx::display_list::OpaqueNode;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use script_layout_interface::restyle_damage::RestyleDamage;
use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use style::animation::{Animation, update_style_for_animation};
use time;

/// Processes any new animations that were discovered after style recalculation.
/// Also expire any old animations that have completed, inserting them into
/// `expired_animations`.
pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
                              running_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
                              expired_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
                              new_animations_receiver: &Receiver<Animation>,
                              pipeline_id: PipelineId) {
    let mut new_running_animations = vec![];
    while let Ok(animation) = new_animations_receiver.try_recv() {
        let should_push = match animation {
            Animation::Transition(..) => true,
            Animation::Keyframes(ref node, ref name, ref state) => {
                // If the animation was already present in the list for the
                // node, just update its state, else push the new animation to
                // run.
                if let Some(ref mut animations) = running_animations.get_mut(node) {
                    // TODO: This being linear is probably not optimal.
                    // Also, we should move this logic somehow.
                    match animations.iter_mut().find(|anim| match **anim {
                        Animation::Keyframes(_, ref anim_name, _) => *name == *anim_name,
                        Animation::Transition(..) => false,
                    }) {
                        Some(mut anim) => {
                            debug!("update_animation_state: Found other animation {}", name);
                            match *anim {
                                Animation::Keyframes(_, _, ref mut anim_state) => {
                                    anim_state.update_from_other(&state);
                                    false
                                }
                                _ => unreachable!(),
                            }
                        }
                        None => true,
                    }
                } else {
                    true
                }
            }
        };

        if should_push {
            new_running_animations.push(animation);
        }
    }

    if running_animations.is_empty() && new_running_animations.is_empty() {
        // Nothing to do. Return early so we don't flood the compositor with
        // `ChangeRunningAnimationsState` messages.
        return
    }

    let now = time::precise_time_s();
    // Expire old running animations.
    let mut keys_to_remove = vec![];
    for (key, running_animations) in running_animations.iter_mut() {
        let mut animations_still_running = vec![];
        for mut running_animation in running_animations.drain(..) {
            let still_running = !running_animation.is_expired() && match running_animation {
                Animation::Transition(_, started_at, ref frame, _expired) => {
                    now < started_at + frame.duration
                }
                Animation::Keyframes(_, _, ref mut state) => {
                    // This animation is still running, or we need to keep
                    // iterating.
                    now < state.started_at + state.duration || state.tick()
                }
            };

            if still_running {
                animations_still_running.push(running_animation);
                continue
            }

            expired_animations.entry(*key)
                              .or_insert_with(Vec::new)
                              .push(running_animation);
        }

        if animations_still_running.is_empty() {
            keys_to_remove.push(*key);
        } else {
            *running_animations = animations_still_running
        }
    }

    for key in keys_to_remove {
        running_animations.remove(&key).unwrap();
    }

    // Add new running animations.
    for new_running_animation in new_running_animations {
        running_animations.entry(*new_running_animation.node())
                          .or_insert_with(Vec::new)
                          .push(new_running_animation);
    }

    let animation_state = if running_animations.is_empty() {
        AnimationState::NoAnimationsPresent
    } else {
        AnimationState::AnimationsPresent
    };

    constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, animation_state))
                      .unwrap();
}

/// Recalculates style for a set of animations. This does *not* run with the DOM
/// lock held.
pub fn recalc_style_for_animations(context: &SharedLayoutContext,
                                   flow: &mut Flow,
                                   animations: &HashMap<OpaqueNode, Vec<Animation>>) {
    let mut damage = RestyleDamage::empty();
    flow.mutate_fragments(&mut |fragment| {
        if let Some(ref animations) = animations.get(&fragment.node) {
            for animation in animations.iter() {
                update_style_for_animation(&context.style_context,
                                           animation,
                                           &mut fragment.style,
                                           Some(&mut damage));
            }
        }
    });

    let base = flow::mut_base(flow);
    base.restyle_damage.insert(damage);
    for kid in base.children.iter_mut() {
        recalc_style_for_animations(context, kid, animations)
    }
}
<commit_msg>layout: Simplify logic in layout/animation.rs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS transitions and animations.

use context::SharedLayoutContext;
use flow::{self, Flow};
use gfx::display_list::OpaqueNode;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use script_layout_interface::restyle_damage::RestyleDamage;
use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use style::animation::{Animation, update_style_for_animation};
use time;

/// Processes any new animations that were discovered after style recalculation.
/// Also expire any old animations that have completed, inserting them into
/// `expired_animations`.
pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
                              running_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
                              expired_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
                              new_animations_receiver: &Receiver<Animation>,
                              pipeline_id: PipelineId) {
    let mut new_running_animations = vec![];
    while let Ok(animation) = new_animations_receiver.try_recv() {
        let mut should_push = true;
        if let Animation::Keyframes(ref node, ref name, ref state) = animation {
            // If the animation was already present in the list for the
            // node, just update its state, else push the new animation to
            // run.
            if let Some(ref mut animations) = running_animations.get_mut(node) {
                // TODO: This being linear is probably not optimal.
                for mut anim in animations.iter_mut() {
                    if let Animation::Keyframes(_, ref anim_name, ref mut anim_state) = *anim {
                        if *name == *anim_name {
                            debug!("update_animation_state: Found other animation {}", name);
                            anim_state.update_from_other(&state);
                            should_push = false;
                            break;
                        }
                    }
                }
            }
        }

        if should_push {
            new_running_animations.push(animation);
        }
    }

    if running_animations.is_empty() && new_running_animations.is_empty() {
        // Nothing to do. Return early so we don't flood the compositor with
        // `ChangeRunningAnimationsState` messages.
        return
    }

    let now = time::precise_time_s();
    // Expire old running animations.
    //
    // TODO: Do not expunge Keyframes animations, since we need that state if
    // the animation gets re-triggered. Probably worth splitting in two
    // different maps, or at least using a linked list?
    let mut keys_to_remove = vec![];
    for (key, running_animations) in running_animations.iter_mut() {
        let mut animations_still_running = vec![];
        for mut running_animation in running_animations.drain(..) {
            let still_running = !running_animation.is_expired() && match running_animation {
                Animation::Transition(_, started_at, ref frame, _expired) => {
                    now < started_at + frame.duration
                }
                Animation::Keyframes(_, _, ref mut state) => {
                    // This animation is still running, or we need to keep
                    // iterating.
                    now < state.started_at + state.duration || state.tick()
                }
            };

            if still_running {
                animations_still_running.push(running_animation);
                continue
            }

            expired_animations.entry(*key)
                              .or_insert_with(Vec::new)
                              .push(running_animation);
        }

        if animations_still_running.is_empty() {
            keys_to_remove.push(*key);
        } else {
            *running_animations = animations_still_running
        }
    }

    for key in keys_to_remove {
        running_animations.remove(&key).unwrap();
    }

    // Add new running animations.
    for new_running_animation in new_running_animations {
        running_animations.entry(*new_running_animation.node())
                          .or_insert_with(Vec::new)
                          .push(new_running_animation);
    }

    let animation_state = if running_animations.is_empty() {
        AnimationState::NoAnimationsPresent
    } else {
        AnimationState::AnimationsPresent
    };

    constellation_chan.send(ConstellationMsg::ChangeRunningAnimationsState(pipeline_id, animation_state))
                      .unwrap();
}

/// Recalculates style for a set of animations. This does *not* run with the DOM
/// lock held.
pub fn recalc_style_for_animations(context: &SharedLayoutContext,
                                   flow: &mut Flow,
                                   animations: &HashMap<OpaqueNode, Vec<Animation>>) {
    let mut damage = RestyleDamage::empty();
    flow.mutate_fragments(&mut |fragment| {
        if let Some(ref animations) = animations.get(&fragment.node) {
            for animation in animations.iter() {
                update_style_for_animation(&context.style_context,
                                           animation,
                                           &mut fragment.style,
                                           Some(&mut damage));
            }
        }
    });

    let base = flow::mut_base(flow);
    base.restyle_damage.insert(damage);
    for kid in base.children.iter_mut() {
        recalc_style_for_animations(context, kid, animations)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements sequential traversal over the DOM tree.

#![deny(missing_docs)]

use context::{StyleContext, ThreadLocalStyleContext};
use dom::{TElement, TNode};
use std::collections::VecDeque;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

struct WorkItem<N: TNode>(N, usize);

/// Do a sequential DOM traversal for layout or styling, generic over `D`.
pub fn traverse_dom<E, D>(traversal: &D,
                          root: E,
                          token: PreTraverseToken)
    where E: TElement,
          D: DomTraversal<E>,
{
    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    debug_assert!(!traversal.is_parallel());
    debug_assert!(token.should_traverse());

    let mut discovered = VecDeque::<WorkItem<E::ConcreteNode>>::with_capacity(16);
    let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
    let mut context = StyleContext {
        shared: traversal.shared_context(),
        thread_local: &mut tlc,
    };

    let root_depth = root.depth();
    discovered.push_back(WorkItem(root.as_node(), root_depth));

    // Process the nodes breadth-first, just like the parallel traversal does.
    // This helps keep similar traversal characteristics for the style sharing
    // cache.
    while let Some(WorkItem(node, depth)) = discovered.pop_front() {
        let mut children_to_process = 0isize;
        let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
        traversal.process_preorder(&traversal_data, &mut context, node, |n| {
            children_to_process += 1;
            discovered.push_back(WorkItem(n, depth + 1));
        });

        traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
                                             node, children_to_process);
    }

    // Dump statistics to stdout if requested.
    if dump_stats {
        context.thread_local.statistics.finish(traversal, start_time.unwrap());
        if context.thread_local.statistics.is_large_traversal() {
            println!("{}", context.thread_local.statistics);
        }
    }
}
<commit_msg>Stop storing depth per-node in the sequential traversal.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements sequential traversal over the DOM tree.

#![deny(missing_docs)]

use context::{StyleContext, ThreadLocalStyleContext};
use dom::{SendNode, TElement, TNode};
use parallel::WORK_UNIT_MAX;
use std::collections::VecDeque;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

/// Do a sequential DOM traversal for layout or styling, generic over `D`.
pub fn traverse_dom<E, D>(traversal: &D,
                          root: E,
                          token: PreTraverseToken)
    where E: TElement,
          D: DomTraversal<E>,
{
    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    debug_assert!(!traversal.is_parallel());
    debug_assert!(token.should_traverse());

    let mut discovered =
        VecDeque::<SendNode<E::ConcreteNode>>::with_capacity(WORK_UNIT_MAX * 2);
    let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
    let mut context = StyleContext {
        shared: traversal.shared_context(),
        thread_local: &mut tlc,
    };

    // Process the nodes breadth-first, just like the parallel traversal does.
    // This helps keep similar traversal characteristics for the style sharing
    // cache.
    let mut depth = root.depth();
    let mut nodes_remaining_at_current_depth = 1;
    discovered.push_back(unsafe { SendNode::new(root.as_node()) });
    while let Some(node) = discovered.pop_front() {
        let mut children_to_process = 0isize;
        let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
        traversal.process_preorder(&traversal_data, &mut context, *node, |n| {
            children_to_process += 1;
            discovered.push_back(unsafe { SendNode::new(n) });
        });

        traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
                                             *node, children_to_process);
        nodes_remaining_at_current_depth -= 1;
        if nodes_remaining_at_current_depth == 0 {
            depth += 1;
            nodes_remaining_at_current_depth = discovered.len();
        }
    }

    // Dump statistics to stdout if requested.
    if dump_stats {
        context.thread_local.statistics.finish(traversal, start_time.unwrap());
        if context.thread_local.statistics.is_large_traversal() {
            println!("{}", context.thread_local.statistics);
        }
    }
}
<|endoftext|>


<commit_before>use stb_image::*;
use stb_image::bindgen::*;
use libc::types::os::arch::c95::c_int;
use ptr::{is_null, to_unsafe_ptr};
use str::as_c_str;
use vec::as_imm_buf;
use vec::raw::from_buf_raw;

pub struct Image<T> {
    width   : uint,
    height  : uint,
    depth   : uint,
    data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : move data,
    }
}

enum LoadResult {
    Error,
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

pub fn load(path: ~str) -> LoadResult {
    let force_depth = 0;
    load_with_depth(move path, force_depth, false)
}

priv fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = from_buf_raw(buf, (w * h * d) as uint);
        libc::free(buf as *c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: ~str, force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width   = 0 as c_int;
            let mut height  = 0 as c_int;
            let mut depth   = 0 as c_int;
            as_c_str(path, |bytes| {
                if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                    let buffer = stbi_loadf(
                        bytes, to_unsafe_ptr(&width), to_unsafe_ptr(&height),
                        to_unsafe_ptr(&depth), force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageF32( load_internal(buffer,width,height,depth) )
                    }
                } else {
                    let buffer = stbi_load(
                        bytes, to_unsafe_ptr(&width), to_unsafe_ptr(&height),
                        to_unsafe_ptr(&depth), force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageU8( load_internal(buffer,width,height,depth) )
                    }
                }
            })
        }
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width = 0 as c_int;
            let mut height = 0 as c_int;
            let mut depth = 0 as c_int;
            as_imm_buf(buffer, |bytes, len| {
                if !convert_hdr && stbi_is_hdr_from_memory(bytes,len as c_int)!=0   {
                    let buffer = stbi_loadf_from_memory(
                        bytes, len as c_int, to_unsafe_ptr(&width),
                        to_unsafe_ptr(&height), to_unsafe_ptr(&depth),
                        force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageF32( load_internal(buffer,width,height,depth) )
                    }
                } else {
                    let buffer = stbi_load_from_memory(
                        bytes, len as c_int, to_unsafe_ptr(&width),
                        to_unsafe_ptr(&height), to_unsafe_ptr(&depth),
                        force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageU8( load_internal(buffer,width,height,depth) )
                    }
                }
            })
        }
    }
}
<commit_msg>Fix force-depth<commit_after>use stb_image::*;
use stb_image::bindgen::*;
use libc::types::os::arch::c95::c_int;
use ptr::{is_null, to_unsafe_ptr};
use str::as_c_str;
use vec::as_imm_buf;
use vec::raw::from_buf_raw;

pub struct Image<T> {
    width   : uint,
    height  : uint,
    depth   : uint,
    data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : move data,
    }
}

enum LoadResult {
    Error,
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

pub fn load(path: ~str) -> LoadResult {
    let force_depth = 0;
    load_with_depth(move path, force_depth, false)
}

priv fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = from_buf_raw(buf, (w * h * d) as uint);
        libc::free(buf as *c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: ~str, force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width   = 0 as c_int;
            let mut height  = 0 as c_int;
            let mut depth   = 0 as c_int;
            as_c_str(path, |bytes| {
                if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                    let buffer = stbi_loadf(
                        bytes, to_unsafe_ptr(&width), to_unsafe_ptr(&height),
                        to_unsafe_ptr(&depth), force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageF32( load_internal(buffer,width,height,depth) )
                    }
                } else {
                    let buffer = stbi_load(
                        bytes, to_unsafe_ptr(&width), to_unsafe_ptr(&height),
                        to_unsafe_ptr(&depth), force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        ImageU8( load_internal(buffer,width,height,depth) )
                    }
                }
            })
        }
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        do task::unkillable {
            let mut width = 0 as c_int;
            let mut height = 0 as c_int;
            let mut depth = 0 as c_int;
            as_imm_buf(buffer, |bytes, len| {
                if !convert_hdr && stbi_is_hdr_from_memory(bytes,len as c_int)!=0   {
                    let buffer = stbi_loadf_from_memory(
                        bytes, len as c_int, to_unsafe_ptr(&width),
                        to_unsafe_ptr(&height), to_unsafe_ptr(&depth),
                        force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                        ImageF32( load_internal(buffer,width,height,actual_depth) )
                    }
                } else {
                    let buffer = stbi_load_from_memory(
                        bytes, len as c_int, to_unsafe_ptr(&width),
                        to_unsafe_ptr(&height), to_unsafe_ptr(&depth),
                        force_depth as c_int);
                    if is_null(buffer) {
                        Error
                    } else {
                        let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                        ImageU8( load_internal(buffer,width,height,actual_depth) )
                    }
                }
            })
        }
    }
}
<|endoftext|>


<commit_before>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]

use std::fs::{
    File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename,
};
use std::ffi::CString;
use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

extern crate libc;

fn main() {
    test_file();
    test_file_clone();
    test_file_create_new();
    test_seek();
    test_metadata();
    test_file_set_len();
    test_file_sync();
    test_symlink();
    test_errors();
    test_rename();
    test_directory();
    test_dup_stdout_stderr();
}

fn tmp() -> PathBuf {
    std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir())
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let path = tmp().join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

/// Prepare directory: compute directory name and make sure it does not exist.
fn prepare_dir(dirname: &str) -> PathBuf {
    let path = tmp().join(&dirname);
    // Clean the directory for robustness.
    remove_dir_all(&path).ok();
    path
}

/// Prepare like above, and also write some initial content to the file.
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
    let path = prepare(filename);
    let mut file = File::create(&path).unwrap();
    file.write(content).unwrap();
    path
}

fn test_file() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_file.txt");

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_create_new() {
    let path = prepare("miri_test_fs_file_create_new.txt");

    // Creating a new file that doesn't yet exist should succeed.
    OpenOptions::new().write(true).create_new(true).open(&path).unwrap();
    // Creating a new file that already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind());
    // Optionally creating a new file that already exists should succeed.
    OpenOptions::new().write(true).create(true).open(&path).unwrap();

    // Clean up
    remove_file(&path).unwrap();
}

fn test_seek() {
    let bytes = b"Hello, entire World!\n";
    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let bytes = b"Hello, meta-World!\n";
    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_set_len() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_set_len.txt", bytes);

    // Test extending the file
    let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
    let bytes_extended = b"Hello, World!\n\x00\x00\x00\x00\x00\x00";
    file.set_len(20).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes_extended, contents.as_slice());

    // Test truncating the file
    file.seek(SeekFrom::Start(0)).unwrap();
    file.set_len(10).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[..10], contents.as_slice());

    // Can't use set_len on a file not opened for writing
    let file = OpenOptions::new().read(true).open(&path).unwrap();
    assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind());

    remove_file(&path).unwrap();
}

fn test_file_sync() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_sync.txt", bytes);

    // Test that we can call sync_data and sync_all (can't readily test effects of this operation)
    let file = OpenOptions::new().write(true).open(&path).unwrap();
    file.sync_data().unwrap();
    file.sync_all().unwrap();

    // Test that we can call sync_data and sync_all on a file opened for reading.
    let file = File::open(&path).unwrap();
    file.sync_data().unwrap();
    file.sync_all().unwrap();

    remove_file(&path).unwrap();
}

fn test_symlink() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
    let symlink_path = prepare("miri_test_fs_symlink.txt");

    // Creating a symbolic link should succeed.
    #[cfg(unix)]
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    #[cfg(windows)]
    std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    #[cfg(unix)]
    {
        use std::os::unix::ffi::OsStrExt;

        let expected_path = path.as_os_str().as_bytes();

        // Test that the expected string gets written to a buffer of proper
        // length, and that a trailing null byte is not written
        let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
        let symlink_c_ptr = symlink_c_str.as_ptr();

        // Make the buf one byte larger than it needs to be,
        // and check that the last byte is not overwritten
        let mut large_buf = vec![0xFF; expected_path.len() + 1];
        let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) };
        assert_eq!(res, large_buf.len() as isize - 1);
        // Check that the resovled path was properly written into the buf
        assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path);
        assert_eq!(large_buf.last(), Some(&0xFF));

        // Test that the resolved path is truncated if the provided buffer
        // is too small.
        let mut small_buf = [0u8; 2];
        let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) };
        assert_eq!(res, small_buf.len() as isize);
        assert_eq!(small_buf, &expected_path[..small_buf.len()]);

        // Test that we report a proper error for a missing path.
        let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap();
        let res = unsafe { libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) };
        assert_eq!(res, -1);
        assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
    }

    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_errors.txt");

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);

    // Renaming should succeed
    rename(&path1, &path2).unwrap();
    // Check that the old file path isn't present
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    // Check that the file has moved successfully
    assert!(path2.metadata().unwrap().is_file());

    // Renaming a nonexistent file should fail
    assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind());

    remove_file(&path2).unwrap();
}

fn test_directory() {
    let dir_path = prepare_dir("miri_test_fs_dir");
    // Creating a directory should succeed.
    create_dir(&dir_path).unwrap();
    // Test that the metadata of a directory is correct.
    assert!(dir_path.metadata().unwrap().is_dir());
    // Creating a directory when it already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, create_dir(&dir_path).unwrap_err().kind());

    // Create some files inside the directory
    let path_1 = dir_path.join("test_file_1");
    drop(File::create(&path_1).unwrap());
    let path_2 = dir_path.join("test_file_2");
    drop(File::create(&path_2).unwrap());
    // Test that the files are present inside the directory
    let dir_iter = read_dir(&dir_path).unwrap();
    let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    file_names.sort_unstable();
    assert_eq!(file_names, vec!["test_file_1", "test_file_2"]);
    // Clean up the files in the directory
    remove_file(&path_1).unwrap();
    remove_file(&path_2).unwrap();
    // Now there should be nothing left in the directory.
    let dir_iter = read_dir(&dir_path).unwrap();
    let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    assert!(file_names.is_empty());

    // Deleting the directory should succeed.
    remove_dir(&dir_path).unwrap();
    // Reading the metadata of a non-existent directory should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind());
}

fn test_dup_stdout_stderr() {
    let bytes = b"hello dup fd\n";
    unsafe {
        let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0);
        let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0);
        libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len());
        libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len());
    }
}
<commit_msg>Add trailing punctuation<commit_after>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]

use std::fs::{
    File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename,
};
use std::ffi::CString;
use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

extern crate libc;

fn main() {
    test_file();
    test_file_clone();
    test_file_create_new();
    test_seek();
    test_metadata();
    test_file_set_len();
    test_file_sync();
    test_symlink();
    test_errors();
    test_rename();
    test_directory();
    test_dup_stdout_stderr();
}

fn tmp() -> PathBuf {
    std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir())
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let path = tmp().join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

/// Prepare directory: compute directory name and make sure it does not exist.
fn prepare_dir(dirname: &str) -> PathBuf {
    let path = tmp().join(&dirname);
    // Clean the directory for robustness.
    remove_dir_all(&path).ok();
    path
}

/// Prepare like above, and also write some initial content to the file.
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
    let path = prepare(filename);
    let mut file = File::create(&path).unwrap();
    file.write(content).unwrap();
    path
}

fn test_file() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_file.txt");

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_create_new() {
    let path = prepare("miri_test_fs_file_create_new.txt");

    // Creating a new file that doesn't yet exist should succeed.
    OpenOptions::new().write(true).create_new(true).open(&path).unwrap();
    // Creating a new file that already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind());
    // Optionally creating a new file that already exists should succeed.
    OpenOptions::new().write(true).create(true).open(&path).unwrap();

    // Clean up
    remove_file(&path).unwrap();
}

fn test_seek() {
    let bytes = b"Hello, entire World!\n";
    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let bytes = b"Hello, meta-World!\n";
    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_set_len() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_set_len.txt", bytes);

    // Test extending the file
    let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
    let bytes_extended = b"Hello, World!\n\x00\x00\x00\x00\x00\x00";
    file.set_len(20).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes_extended, contents.as_slice());

    // Test truncating the file
    file.seek(SeekFrom::Start(0)).unwrap();
    file.set_len(10).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[..10], contents.as_slice());

    // Can't use set_len on a file not opened for writing
    let file = OpenOptions::new().read(true).open(&path).unwrap();
    assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind());

    remove_file(&path).unwrap();
}

fn test_file_sync() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_sync.txt", bytes);

    // Test that we can call sync_data and sync_all (can't readily test effects of this operation)
    let file = OpenOptions::new().write(true).open(&path).unwrap();
    file.sync_data().unwrap();
    file.sync_all().unwrap();

    // Test that we can call sync_data and sync_all on a file opened for reading.
    let file = File::open(&path).unwrap();
    file.sync_data().unwrap();
    file.sync_all().unwrap();

    remove_file(&path).unwrap();
}

fn test_symlink() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
    let symlink_path = prepare("miri_test_fs_symlink.txt");

    // Creating a symbolic link should succeed.
    #[cfg(unix)]
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    #[cfg(windows)]
    std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    #[cfg(unix)]
    {
        use std::os::unix::ffi::OsStrExt;

        let expected_path = path.as_os_str().as_bytes();

        // Test that the expected string gets written to a buffer of proper
        // length, and that a trailing null byte is not written.
        let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
        let symlink_c_ptr = symlink_c_str.as_ptr();

        // Make the buf one byte larger than it needs to be,
        // and check that the last byte is not overwritten.
        let mut large_buf = vec![0xFF; expected_path.len() + 1];
        let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) };
        assert_eq!(res, large_buf.len() as isize - 1);
        // Check that the resovled path was properly written into the buf.
        assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path);
        assert_eq!(large_buf.last(), Some(&0xFF));

        // Test that the resolved path is truncated if the provided buffer
        // is too small.
        let mut small_buf = [0u8; 2];
        let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) };
        assert_eq!(res, small_buf.len() as isize);
        assert_eq!(small_buf, &expected_path[..small_buf.len()]);

        // Test that we report a proper error for a missing path.
        let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap();
        let res = unsafe { libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) };
        assert_eq!(res, -1);
        assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
    }

    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_errors.txt");

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);

    // Renaming should succeed
    rename(&path1, &path2).unwrap();
    // Check that the old file path isn't present
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    // Check that the file has moved successfully
    assert!(path2.metadata().unwrap().is_file());

    // Renaming a nonexistent file should fail
    assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind());

    remove_file(&path2).unwrap();
}

fn test_directory() {
    let dir_path = prepare_dir("miri_test_fs_dir");
    // Creating a directory should succeed.
    create_dir(&dir_path).unwrap();
    // Test that the metadata of a directory is correct.
    assert!(dir_path.metadata().unwrap().is_dir());
    // Creating a directory when it already exists should fail.
    assert_eq!(ErrorKind::AlreadyExists, create_dir(&dir_path).unwrap_err().kind());

    // Create some files inside the directory
    let path_1 = dir_path.join("test_file_1");
    drop(File::create(&path_1).unwrap());
    let path_2 = dir_path.join("test_file_2");
    drop(File::create(&path_2).unwrap());
    // Test that the files are present inside the directory
    let dir_iter = read_dir(&dir_path).unwrap();
    let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    file_names.sort_unstable();
    assert_eq!(file_names, vec!["test_file_1", "test_file_2"]);
    // Clean up the files in the directory
    remove_file(&path_1).unwrap();
    remove_file(&path_2).unwrap();
    // Now there should be nothing left in the directory.
    let dir_iter = read_dir(&dir_path).unwrap();
    let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::<Vec<_>>();
    assert!(file_names.is_empty());

    // Deleting the directory should succeed.
    remove_dir(&dir_path).unwrap();
    // Reading the metadata of a non-existent directory should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind());
}

fn test_dup_stdout_stderr() {
    let bytes = b"hello dup fd\n";
    unsafe {
        let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0);
        let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0);
        libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len());
        libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len());
    }
}
<|endoftext|>