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

#![stable(feature = "metadata_ext", since = "1.1.0")]

use libc;

use fs::Metadata;
use sys_common::AsInner;

#[allow(deprecated)]
use os::linux::raw;

/// OS-specific extension methods for `fs::Metadata`
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
    /// Gain a reference to the underlying `stat` structure which contains
    /// the raw information returned by the OS.
    ///
    /// The contents of the returned `stat` are **not** consistent across
    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
    /// cross-Unix abstractions contained within the raw stat.
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    #[rustc_deprecated(since = "1.8.0",
                       reason = "deprecated in favor of the accessor \
                                 methods of this trait")]
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat;

    /// Returns the device ID on which this file resides.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_dev(&self) -> u64;
    /// Returns the inode number.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ino(&self) -> u64;
    /// Returns the file type and mode.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mode(&self) -> u32;
    /// Returns the number of hard links to file.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_nlink(&self) -> u64;
    /// Returns the user ID of the file owner.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_uid(&self) -> u32;
    /// Returns the group ID of the file owner.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_gid(&self) -> u32;
    /// Returns the device ID that this file represents. Only relevant for special file.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_rdev(&self) -> u64;
    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
    ///
    /// The size of a symbolic link is the length of the pathname it contains,
    /// without a terminating null byte.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_size(&self) -> u64;
    /// Returns the last access time.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime(&self) -> i64;
    /// Returns the last access time, nano seconds part.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime_nsec(&self) -> i64;
    /// Returns the last modification time.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime(&self) -> i64;
    /// Returns the last modification time, nano seconds part.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime_nsec(&self) -> i64;
    /// Returns the last status change time.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime(&self) -> i64;
    /// Returns the last status change time, nano seconds part.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime_nsec(&self) -> i64;
    /// Returns the "preferred" blocksize for efficient filesystem I/O.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blksize(&self) -> u64;
    /// Returns the number of blocks allocated to the file, 512-byte units.
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blocks(&self) -> u64;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat {
        unsafe {
            &*(self.as_inner().as_inner() as *const libc::stat64
                                          as *const raw::stat)
        }
    }
    fn st_dev(&self) -> u64 {
        self.as_inner().as_inner().st_dev as u64
    }
    fn st_ino(&self) -> u64 {
        self.as_inner().as_inner().st_ino as u64
    }
    fn st_mode(&self) -> u32 {
        self.as_inner().as_inner().st_mode as u32
    }
    fn st_nlink(&self) -> u64 {
        self.as_inner().as_inner().st_nlink as u64
    }
    fn st_uid(&self) -> u32 {
        self.as_inner().as_inner().st_uid as u32
    }
    fn st_gid(&self) -> u32 {
        self.as_inner().as_inner().st_gid as u32
    }
    fn st_rdev(&self) -> u64 {
        self.as_inner().as_inner().st_rdev as u64
    }
    fn st_size(&self) -> u64 {
        self.as_inner().as_inner().st_size as u64
    }
    fn st_atime(&self) -> i64 {
        self.as_inner().as_inner().st_atime as i64
    }
    fn st_atime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_atime_nsec as i64
    }
    fn st_mtime(&self) -> i64 {
        self.as_inner().as_inner().st_mtime as i64
    }
    fn st_mtime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_mtime_nsec as i64
    }
    fn st_ctime(&self) -> i64 {
        self.as_inner().as_inner().st_ctime as i64
    }
    fn st_ctime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_ctime_nsec as i64
    }
    fn st_blksize(&self) -> u64 {
        self.as_inner().as_inner().st_blksize as u64
    }
    fn st_blocks(&self) -> u64 {
        self.as_inner().as_inner().st_blocks as u64
    }
}
<commit_msg>Add missing code examples<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![stable(feature = "metadata_ext", since = "1.1.0")]

use libc;

use fs::Metadata;
use sys_common::AsInner;

#[allow(deprecated)]
use os::linux::raw;

/// OS-specific extension methods for `fs::Metadata`
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
    /// Gain a reference to the underlying `stat` structure which contains
    /// the raw information returned by the OS.
    ///
    /// The contents of the returned [`stat`] are **not** consistent across
    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
    /// cross-Unix abstractions contained within the raw stat.
    ///
    /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// let stat = meta.as_raw_stat();
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext", since = "1.1.0")]
    #[rustc_deprecated(since = "1.8.0",
                       reason = "deprecated in favor of the accessor \
                                 methods of this trait")]
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat;

    /// Returns the device ID on which this file resides.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_dev());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_dev(&self) -> u64;
    /// Returns the inode number.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_ino());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ino(&self) -> u64;
    /// Returns the file type and mode.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_mode());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mode(&self) -> u32;
    /// Returns the number of hard links to file.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_nlink());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_nlink(&self) -> u64;
    /// Returns the user ID of the file owner.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_uid());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_uid(&self) -> u32;
    /// Returns the group ID of the file owner.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_gid());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_gid(&self) -> u32;
    /// Returns the device ID that this file represents. Only relevant for special file.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_rdev());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_rdev(&self) -> u64;
    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
    ///
    /// The size of a symbolic link is the length of the pathname it contains,
    /// without a terminating null byte.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_size());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_size(&self) -> u64;
    /// Returns the last access time.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_atime());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime(&self) -> i64;
    /// Returns the last access time, nano seconds part.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_atime_nsec());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_atime_nsec(&self) -> i64;
    /// Returns the last modification time.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_mtime());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime(&self) -> i64;
    /// Returns the last modification time, nano seconds part.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_mtime_nsec());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_mtime_nsec(&self) -> i64;
    /// Returns the last status change time.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_ctime());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime(&self) -> i64;
    /// Returns the last status change time, nano seconds part.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_ctime_nsec());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_ctime_nsec(&self) -> i64;
    /// Returns the "preferred" blocksize for efficient filesystem I/O.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_blksize());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blksize(&self) -> u64;
    /// Returns the number of blocks allocated to the file, 512-byte units.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use std::os::unix::prelude::*;
    ///
    /// # use std::io;
    /// # fn f() -> io::Result<()> {
    /// let meta = fs::metadata("some_file")?;
    /// println!("{}", meta.st_blocks());
    /// # Ok(())
    /// # }
    /// ```
    #[stable(feature = "metadata_ext2", since = "1.8.0")]
    fn st_blocks(&self) -> u64;
}

#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
    #[allow(deprecated)]
    fn as_raw_stat(&self) -> &raw::stat {
        unsafe {
            &*(self.as_inner().as_inner() as *const libc::stat64
                                          as *const raw::stat)
        }
    }
    fn st_dev(&self) -> u64 {
        self.as_inner().as_inner().st_dev as u64
    }
    fn st_ino(&self) -> u64 {
        self.as_inner().as_inner().st_ino as u64
    }
    fn st_mode(&self) -> u32 {
        self.as_inner().as_inner().st_mode as u32
    }
    fn st_nlink(&self) -> u64 {
        self.as_inner().as_inner().st_nlink as u64
    }
    fn st_uid(&self) -> u32 {
        self.as_inner().as_inner().st_uid as u32
    }
    fn st_gid(&self) -> u32 {
        self.as_inner().as_inner().st_gid as u32
    }
    fn st_rdev(&self) -> u64 {
        self.as_inner().as_inner().st_rdev as u64
    }
    fn st_size(&self) -> u64 {
        self.as_inner().as_inner().st_size as u64
    }
    fn st_atime(&self) -> i64 {
        self.as_inner().as_inner().st_atime as i64
    }
    fn st_atime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_atime_nsec as i64
    }
    fn st_mtime(&self) -> i64 {
        self.as_inner().as_inner().st_mtime as i64
    }
    fn st_mtime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_mtime_nsec as i64
    }
    fn st_ctime(&self) -> i64 {
        self.as_inner().as_inner().st_ctime as i64
    }
    fn st_ctime_nsec(&self) -> i64 {
        self.as_inner().as_inner().st_ctime_nsec as i64
    }
    fn st_blksize(&self) -> u64 {
        self.as_inner().as_inner().st_blksize as u64
    }
    fn st_blocks(&self) -> u64 {
        self.as_inner().as_inner().st_blocks as u64
    }
}
<|endoftext|>


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

//! A wrapper around any Reader to treat it as an RNG.

use collections::Collection;
use io::Reader;
use rand::Rng;
use result::{Ok, Err};

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// It will fail if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use std::rand::{reader, Rng};
/// use std::io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8)));
/// println!("{:x}", rng.gen::<uint>());
/// ```
pub struct ReaderRng<R> {
    reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.read_at_least(v.len(), v) {
            Ok(_) => {}
            Err(e) => fail!("ReaderRng.fill_bytes error: {}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::ReaderRng;
    use io::MemReader;
    use mem;
    use rand::Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
                     0  , 0, 0, 0, 0, 0, 0, 2,
                     0,   0, 0, 0, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u64(), mem::to_be64(1));
        assert_eq!(rng.next_u64(), mem::to_be64(2));
        assert_eq!(rng.next_u64(), mem::to_be64(3));
    }
    #[test]
    fn test_reader_rng_u32() {
        let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u32(), mem::to_be32(1));
        assert_eq!(rng.next_u32(), mem::to_be32(2));
        assert_eq!(rng.next_u32(), mem::to_be32(3));
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8, .. 8];

        let mut rng = ReaderRng::new(MemReader::new(Vec::from_slice(v)));
        rng.fill_bytes(w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(vec!()));
        let mut v = [0u8, .. 3];
        rng.fill_bytes(v);
    }
}
<commit_msg>Clean up rustc warnings.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A wrapper around any Reader to treat it as an RNG.

use collections::Collection;
use io::Reader;
use rand::Rng;
use result::{Ok, Err};

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// It will fail if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use std::rand::{reader, Rng};
/// use std::io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8)));
/// println!("{:x}", rng.gen::<uint>());
/// ```
pub struct ReaderRng<R> {
    reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.read_at_least(v.len(), v) {
            Ok(_) => {}
            Err(e) => fail!("ReaderRng.fill_bytes error: {}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::ReaderRng;
    use io::MemReader;
    use rand::Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
                     0  , 0, 0, 0, 0, 0, 0, 2,
                     0,   0, 0, 0, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u64(), 1_u64.to_be());
        assert_eq!(rng.next_u64(), 2_u64.to_be());
        assert_eq!(rng.next_u64(), 3_u64.to_be());
    }
    #[test]
    fn test_reader_rng_u32() {
        let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u32(), 1_u32.to_be());
        assert_eq!(rng.next_u32(), 2_u32.to_be());
        assert_eq!(rng.next_u32(), 3_u32.to_be());
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8, .. 8];

        let mut rng = ReaderRng::new(MemReader::new(v.as_slice().to_vec()));
        rng.fill_bytes(w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(vec!()));
        let mut v = [0u8, .. 3];
        rng.fill_bytes(v);
    }
}
<|endoftext|>


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

//! Timers based on timerfd_create(2)
//!
//! On OSes which support timerfd_create, we can use these much more accurate
//! timers over select() + a timeout (see timer_other.rs). This strategy still
//! employs a worker thread which does the waiting on the timer fds (to send
//! messages away).
//!
//! The worker thread in this implementation uses epoll(7) to block. It
//! maintains a working set of *all* native timers in the process, along with a
//! pipe file descriptor used to communicate that there is data available on the
//! incoming channel to the worker thread. Timers send requests to update their
//! timerfd settings to the worker thread (see the comment above 'oneshot' for
//! why).
//!
//! As with timer_other, timers just using sleep() do not use the timerfd at
//! all. They remove the timerfd from the worker thread and then invoke usleep()
//! to block the calling thread.
//!
//! As with timer_other, all units in this file are in units of millseconds.

use std::comm::Data;
use std::libc;
use std::ptr;
use std::os;
use std::rt::rtio;
use std::hashmap::HashMap;
use std::unstable::intrinsics;

use io::file::FileDesc;
use io::IoResult;
use io::timer_helper;

pub struct Timer {
    priv fd: FileDesc,
    priv on_worker: bool,
}

pub enum Req {
    NewTimer(libc::c_int, Chan<()>, bool, imp::itimerspec),
    RemoveTimer(libc::c_int, Chan<()>),
    Shutdown,
}

fn helper(input: libc::c_int, messages: Port<Req>) {
    let efd = unsafe { imp::epoll_create(10) };
    let _fd1 = FileDesc::new(input, true);
    let _fd2 = FileDesc::new(efd, true);

    fn add(efd: libc::c_int, fd: libc::c_int) {
        let event = imp::epoll_event {
            events: imp::EPOLLIN as u32,
            data: imp::epoll_data_t { fd: fd, pad: 0, }
        };
        let ret = unsafe {
            imp::epoll_ctl(efd, imp::EPOLL_CTL_ADD, fd, &event)
        };
        assert_eq!(ret, 0);
    }
    fn del(efd: libc::c_int, fd: libc::c_int) {
        let event = imp::epoll_event {
            events: 0, data: imp::epoll_data_t { fd: 0, pad: 0, }
        };
        let ret = unsafe {
            imp::epoll_ctl(efd, imp::EPOLL_CTL_DEL, fd, &event)
        };
        assert_eq!(ret, 0);
    }

    add(efd, input);
    let events: [imp::epoll_event, ..16] = unsafe { intrinsics::init() };
    let mut map: HashMap<libc::c_int, (Chan<()>, bool)> = HashMap::new();
    'outer: loop {
        let n = match unsafe {
            imp::epoll_wait(efd, events.as_ptr(),
                            events.len() as libc::c_int, -1)
        } {
            0 => fail!("epoll_wait returned immediately!"),
            -1 => fail!("epoll wait failed: {}", os::last_os_error()),
            n => n
        };

        let mut incoming = false;
        debug!("{} events to process", n);
        for event in events.slice_to(n as uint).iter() {
            let fd = event.data.fd;
            debug!("data on fd {} (input = {})", fd, input);
            if fd == input {
                let mut buf = [0, ..1];
                // drain the input file descriptor of its input
                FileDesc::new(fd, false).inner_read(buf);
                incoming = true;
            } else {
                let mut bits = [0, ..8];
                // drain the timerfd of how many times its fired
                //
                // XXX: should this perform a send() this number of
                //      times?
                FileDesc::new(fd, false).inner_read(bits);
                let remove = {
                    match map.find(&fd).expect("fd unregistered") {
                        &(ref c, oneshot) => !c.try_send(()) || oneshot
                    }
                };
                if remove {
                    map.remove(&fd);
                    del(efd, fd);
                }
            }
        }

        while incoming {
            match messages.try_recv() {
                Data(NewTimer(fd, chan, one, timeval)) => {
                    // acknowledge we have the new channel, we will never send
                    // another message to the old channel
                    chan.send(());

                    // If we haven't previously seen the file descriptor, then
                    // we need to add it to the epoll set.
                    if map.insert(fd, (chan, one)) {
                        add(efd, fd);
                    }

                    // Update the timerfd's time value now that we have control
                    // of the timerfd
                    let ret = unsafe {
                        imp::timerfd_settime(fd, 0, &timeval, ptr::null())
                    };
                    assert_eq!(ret, 0);
                }

                Data(RemoveTimer(fd, chan)) => {
                    if map.remove(&fd) {
                        del(efd, fd);
                    }
                    chan.send(());
                }

                Data(Shutdown) => {
                    assert!(map.len() == 0);
                    break 'outer;
                }

                _ => break,
            }
        }
    }
}

impl Timer {
    pub fn new() -> IoResult<Timer> {
        timer_helper::boot(helper);
        match unsafe { imp::timerfd_create(imp::CLOCK_MONOTONIC, 0) } {
            -1 => Err(super::last_error()),
            n => Ok(Timer { fd: FileDesc::new(n, true), on_worker: false, }),
        }
    }

    pub fn sleep(ms: u64) {
        unsafe { libc::usleep((ms * 1000) as libc::c_uint); }
    }

    fn remove(&mut self) {
        if !self.on_worker { return }

        let (p, c) = Chan::new();
        timer_helper::send(RemoveTimer(self.fd.fd(), c));
        p.recv();
        self.on_worker = false;
    }
}

impl rtio::RtioTimer for Timer {
    fn sleep(&mut self, msecs: u64) {
        self.remove();
        Timer::sleep(msecs);
    }

    // Periodic and oneshot channels are updated by updating the settings on the
    // corresopnding timerfd. The update is not performed on the thread calling
    // oneshot or period, but rather the helper epoll thread. The reason for
    // this is to avoid losing messages and avoid leaking messages across ports.
    //
    // By updating the timerfd on the helper thread, we're guaranteed that all
    // messages for a particular setting of the timer will be received by the
    // new channel/port pair rather than leaking old messages onto the new port
    // or leaking new messages onto the old port.
    //
    // We also wait for the remote thread to actually receive the new settings
    // before returning to guarantee the invariant that when oneshot() and
    // period() return that the old port will never receive any more messages.

    fn oneshot(&mut self, msecs: u64) -> Port<()> {
        let (p, c) = Chan::new();

        let new_value = imp::itimerspec {
            it_interval: imp::timespec { tv_sec: 0, tv_nsec: 0 },
            it_value: imp::timespec {
                tv_sec: (msecs / 1000) as libc::time_t,
                tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long,
            }
        };
        timer_helper::send(NewTimer(self.fd.fd(), c, true, new_value));
        p.recv();
        self.on_worker = true;

        return p;
    }

    fn period(&mut self, msecs: u64) -> Port<()> {
        let (p, c) = Chan::new();

        let spec = imp::timespec {
            tv_sec: (msecs / 1000) as libc::time_t,
            tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long,
        };
        let new_value = imp::itimerspec { it_interval: spec, it_value: spec, };
        timer_helper::send(NewTimer(self.fd.fd(), c, false, new_value));
        p.recv();
        self.on_worker = true;

        return p;
    }
}

impl Drop for Timer {
    fn drop(&mut self) {
        // When the timerfd file descriptor is closed, it will be automatically
        // removed from the epoll set of the worker thread, but we want to make
        // sure that the associated channel is also removed from the worker's
        // hash map.
        self.remove();
    }
}

#[allow(dead_code)]
mod imp {
    use std::libc;

    pub static CLOCK_MONOTONIC: libc::c_int = 1;
    pub static EPOLL_CTL_ADD: libc::c_int = 1;
    pub static EPOLL_CTL_DEL: libc::c_int = 2;
    pub static EPOLL_CTL_MOD: libc::c_int = 3;
    pub static EPOLLIN: libc::c_int = 0x001;
    pub static EPOLLOUT: libc::c_int = 0x004;
    pub static EPOLLPRI: libc::c_int = 0x002;
    pub static EPOLLERR: libc::c_int = 0x008;
    pub static EPOLLRDHUP: libc::c_int = 0x2000;
    pub static EPOLLET: libc::c_int = 1 << 31;
    pub static EPOLLHUP: libc::c_int = 0x010;
    pub static EPOLLONESHOT: libc::c_int = 1 << 30;

    pub struct epoll_event {
        events: u32,
        data: epoll_data_t,
    }

    pub struct epoll_data_t {
        fd: i32,
        pad: u32,
    }

    pub struct timespec {
        tv_sec: libc::time_t,
        tv_nsec: libc::c_long,
    }

    pub struct itimerspec {
        it_interval: timespec,
        it_value: timespec,
    }

    extern {
        pub fn timerfd_create(clockid: libc::c_int,
                              flags: libc::c_int) -> libc::c_int;
        pub fn timerfd_settime(fd: libc::c_int,
                               flags: libc::c_int,
                               new_value: *itimerspec,
                               old_value: *itimerspec) -> libc::c_int;
        pub fn timerfd_gettime(fd: libc::c_int,
                               curr_value: *itimerspec) -> libc::c_int;

        pub fn epoll_create(size: libc::c_int) -> libc::c_int;
        pub fn epoll_ctl(epfd: libc::c_int,
                         op: libc::c_int,
                         fd: libc::c_int,
                         event: *epoll_event) -> libc::c_int;
        pub fn epoll_wait(epfd: libc::c_int,
                          events: *epoll_event,
                          maxevents: libc::c_int,
                          timeout: libc::c_int) -> libc::c_int;
    }
}
<commit_msg>Handle EINTR in epoll for native timers<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Timers based on timerfd_create(2)
//!
//! On OSes which support timerfd_create, we can use these much more accurate
//! timers over select() + a timeout (see timer_other.rs). This strategy still
//! employs a worker thread which does the waiting on the timer fds (to send
//! messages away).
//!
//! The worker thread in this implementation uses epoll(7) to block. It
//! maintains a working set of *all* native timers in the process, along with a
//! pipe file descriptor used to communicate that there is data available on the
//! incoming channel to the worker thread. Timers send requests to update their
//! timerfd settings to the worker thread (see the comment above 'oneshot' for
//! why).
//!
//! As with timer_other, timers just using sleep() do not use the timerfd at
//! all. They remove the timerfd from the worker thread and then invoke usleep()
//! to block the calling thread.
//!
//! As with timer_other, all units in this file are in units of millseconds.

use std::comm::Data;
use std::libc;
use std::ptr;
use std::os;
use std::rt::rtio;
use std::hashmap::HashMap;
use std::unstable::intrinsics;

use io::file::FileDesc;
use io::IoResult;
use io::timer_helper;

pub struct Timer {
    priv fd: FileDesc,
    priv on_worker: bool,
}

pub enum Req {
    NewTimer(libc::c_int, Chan<()>, bool, imp::itimerspec),
    RemoveTimer(libc::c_int, Chan<()>),
    Shutdown,
}

fn helper(input: libc::c_int, messages: Port<Req>) {
    let efd = unsafe { imp::epoll_create(10) };
    let _fd1 = FileDesc::new(input, true);
    let _fd2 = FileDesc::new(efd, true);

    fn add(efd: libc::c_int, fd: libc::c_int) {
        let event = imp::epoll_event {
            events: imp::EPOLLIN as u32,
            data: imp::epoll_data_t { fd: fd, pad: 0, }
        };
        let ret = unsafe {
            imp::epoll_ctl(efd, imp::EPOLL_CTL_ADD, fd, &event)
        };
        assert_eq!(ret, 0);
    }
    fn del(efd: libc::c_int, fd: libc::c_int) {
        let event = imp::epoll_event {
            events: 0, data: imp::epoll_data_t { fd: 0, pad: 0, }
        };
        let ret = unsafe {
            imp::epoll_ctl(efd, imp::EPOLL_CTL_DEL, fd, &event)
        };
        assert_eq!(ret, 0);
    }

    add(efd, input);
    let events: [imp::epoll_event, ..16] = unsafe { intrinsics::init() };
    let mut map: HashMap<libc::c_int, (Chan<()>, bool)> = HashMap::new();
    'outer: loop {
        let n = match unsafe {
            imp::epoll_wait(efd, events.as_ptr(),
                            events.len() as libc::c_int, -1)
        } {
            0 => fail!("epoll_wait returned immediately!"),
            -1 if os::errno() == libc::EINTR as int => { continue }
            -1 => fail!("epoll wait failed: {}", os::last_os_error()),
            n => n
        };

        let mut incoming = false;
        debug!("{} events to process", n);
        for event in events.slice_to(n as uint).iter() {
            let fd = event.data.fd;
            debug!("data on fd {} (input = {})", fd, input);
            if fd == input {
                let mut buf = [0, ..1];
                // drain the input file descriptor of its input
                FileDesc::new(fd, false).inner_read(buf);
                incoming = true;
            } else {
                let mut bits = [0, ..8];
                // drain the timerfd of how many times its fired
                //
                // XXX: should this perform a send() this number of
                //      times?
                FileDesc::new(fd, false).inner_read(bits);
                let remove = {
                    match map.find(&fd).expect("fd unregistered") {
                        &(ref c, oneshot) => !c.try_send(()) || oneshot
                    }
                };
                if remove {
                    map.remove(&fd);
                    del(efd, fd);
                }
            }
        }

        while incoming {
            match messages.try_recv() {
                Data(NewTimer(fd, chan, one, timeval)) => {
                    // acknowledge we have the new channel, we will never send
                    // another message to the old channel
                    chan.send(());

                    // If we haven't previously seen the file descriptor, then
                    // we need to add it to the epoll set.
                    if map.insert(fd, (chan, one)) {
                        add(efd, fd);
                    }

                    // Update the timerfd's time value now that we have control
                    // of the timerfd
                    let ret = unsafe {
                        imp::timerfd_settime(fd, 0, &timeval, ptr::null())
                    };
                    assert_eq!(ret, 0);
                }

                Data(RemoveTimer(fd, chan)) => {
                    if map.remove(&fd) {
                        del(efd, fd);
                    }
                    chan.send(());
                }

                Data(Shutdown) => {
                    assert!(map.len() == 0);
                    break 'outer;
                }

                _ => break,
            }
        }
    }
}

impl Timer {
    pub fn new() -> IoResult<Timer> {
        timer_helper::boot(helper);
        match unsafe { imp::timerfd_create(imp::CLOCK_MONOTONIC, 0) } {
            -1 => Err(super::last_error()),
            n => Ok(Timer { fd: FileDesc::new(n, true), on_worker: false, }),
        }
    }

    pub fn sleep(ms: u64) {
        unsafe { libc::usleep((ms * 1000) as libc::c_uint); }
    }

    fn remove(&mut self) {
        if !self.on_worker { return }

        let (p, c) = Chan::new();
        timer_helper::send(RemoveTimer(self.fd.fd(), c));
        p.recv();
        self.on_worker = false;
    }
}

impl rtio::RtioTimer for Timer {
    fn sleep(&mut self, msecs: u64) {
        self.remove();
        Timer::sleep(msecs);
    }

    // Periodic and oneshot channels are updated by updating the settings on the
    // corresopnding timerfd. The update is not performed on the thread calling
    // oneshot or period, but rather the helper epoll thread. The reason for
    // this is to avoid losing messages and avoid leaking messages across ports.
    //
    // By updating the timerfd on the helper thread, we're guaranteed that all
    // messages for a particular setting of the timer will be received by the
    // new channel/port pair rather than leaking old messages onto the new port
    // or leaking new messages onto the old port.
    //
    // We also wait for the remote thread to actually receive the new settings
    // before returning to guarantee the invariant that when oneshot() and
    // period() return that the old port will never receive any more messages.

    fn oneshot(&mut self, msecs: u64) -> Port<()> {
        let (p, c) = Chan::new();

        let new_value = imp::itimerspec {
            it_interval: imp::timespec { tv_sec: 0, tv_nsec: 0 },
            it_value: imp::timespec {
                tv_sec: (msecs / 1000) as libc::time_t,
                tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long,
            }
        };
        timer_helper::send(NewTimer(self.fd.fd(), c, true, new_value));
        p.recv();
        self.on_worker = true;

        return p;
    }

    fn period(&mut self, msecs: u64) -> Port<()> {
        let (p, c) = Chan::new();

        let spec = imp::timespec {
            tv_sec: (msecs / 1000) as libc::time_t,
            tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long,
        };
        let new_value = imp::itimerspec { it_interval: spec, it_value: spec, };
        timer_helper::send(NewTimer(self.fd.fd(), c, false, new_value));
        p.recv();
        self.on_worker = true;

        return p;
    }
}

impl Drop for Timer {
    fn drop(&mut self) {
        // When the timerfd file descriptor is closed, it will be automatically
        // removed from the epoll set of the worker thread, but we want to make
        // sure that the associated channel is also removed from the worker's
        // hash map.
        self.remove();
    }
}

#[allow(dead_code)]
mod imp {
    use std::libc;

    pub static CLOCK_MONOTONIC: libc::c_int = 1;
    pub static EPOLL_CTL_ADD: libc::c_int = 1;
    pub static EPOLL_CTL_DEL: libc::c_int = 2;
    pub static EPOLL_CTL_MOD: libc::c_int = 3;
    pub static EPOLLIN: libc::c_int = 0x001;
    pub static EPOLLOUT: libc::c_int = 0x004;
    pub static EPOLLPRI: libc::c_int = 0x002;
    pub static EPOLLERR: libc::c_int = 0x008;
    pub static EPOLLRDHUP: libc::c_int = 0x2000;
    pub static EPOLLET: libc::c_int = 1 << 31;
    pub static EPOLLHUP: libc::c_int = 0x010;
    pub static EPOLLONESHOT: libc::c_int = 1 << 30;

    pub struct epoll_event {
        events: u32,
        data: epoll_data_t,
    }

    pub struct epoll_data_t {
        fd: i32,
        pad: u32,
    }

    pub struct timespec {
        tv_sec: libc::time_t,
        tv_nsec: libc::c_long,
    }

    pub struct itimerspec {
        it_interval: timespec,
        it_value: timespec,
    }

    extern {
        pub fn timerfd_create(clockid: libc::c_int,
                              flags: libc::c_int) -> libc::c_int;
        pub fn timerfd_settime(fd: libc::c_int,
                               flags: libc::c_int,
                               new_value: *itimerspec,
                               old_value: *itimerspec) -> libc::c_int;
        pub fn timerfd_gettime(fd: libc::c_int,
                               curr_value: *itimerspec) -> libc::c_int;

        pub fn epoll_create(size: libc::c_int) -> libc::c_int;
        pub fn epoll_ctl(epfd: libc::c_int,
                         op: libc::c_int,
                         fd: libc::c_int,
                         event: *epoll_event) -> libc::c_int;
        pub fn epoll_wait(epfd: libc::c_int,
                          events: *epoll_event,
                          maxevents: libc::c_int,
                          timeout: libc::c_int) -> libc::c_int;
    }
}
<|endoftext|>


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

use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
use context::CodegenCx;

use rustc::ty::layout::Size;

fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
                             ret: &mut ArgType<'tcx>,
                             offset: &mut Size) {
    if !ret.layout.is_aggregate() {
        ret.extend_integer_width_to(64);
    } else {
        ret.make_indirect();
        *offset += cx.tcx.data_layout.pointer_size;
    }
}

fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) {
    let dl = &cx.tcx.data_layout;
    let size = arg.layout.size;
    let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align);

    if arg.layout.is_aggregate() {
        arg.cast_to(Uniform {
            unit: Reg::i64(),
            total: size
        });
        if !offset.is_abi_aligned(align) {
            arg.pad_with(Reg::i64());
        }
    } else {
        arg.extend_integer_width_to(64);
    }

    *offset = offset.abi_align(align) + size.abi_align(align);
}

pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
    let mut offset = Size::from_bytes(0);
    if !fty.ret.is_ignore() {
        classify_ret_ty(cx, &mut fty.ret, &mut offset);
    }

    for arg in &mut fty.args {
        if arg.is_ignore() { continue; }
        classify_arg_ty(cx, arg, &mut offset);
    }
}
<commit_msg>rustc_trans: rewrite mips64 abi<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform};
use context::CodegenCx;
use rustc::ty::layout::{self, Size};

fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) {
    // Always sign extend u32 values on 64-bit mips
    if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
        if let layout::Int(i, signed) = scalar.value {
            if !signed && i.size().bits() == 32 {
                if let PassMode::Direct(ref mut attrs) = arg.mode {
                    attrs.set(ArgAttribute::SExt);
                    return;
                }
            }
        }
    }

    arg.extend_integer_width_to(bits);
}

fn bits_to_int_reg(bits: u64) -> Reg {
    if bits <= 8 {
        Reg::i8()
    } else if bits <= 16 {
        Reg::i16()
    } else if bits <= 32 {
        Reg::i32()
    } else {
        Reg::i64()
    }
}

fn float_reg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &ArgType<'tcx>, i: usize) -> Option<Reg> {
    match ret.layout.field(cx, i).abi {
        layout::Abi::Scalar(ref scalar) => match scalar.value {
            layout::F32 => Some(Reg::f32()),
            layout::F64 => Some(Reg::f64()),
            _ => None
        },
        _ => None
    }
}

fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
    if !ret.layout.is_aggregate() {
        extend_integer_width_mips(ret, 64);
        return;
    }

    let size = ret.layout.size;
    let bits = size.bits();
    if bits <= 128 {
        // Unlike other architectures which return aggregates in registers, MIPS n64 limits the
        // use of float registers to structures (not unions) containing exactly one or two
        // float fields.

        if let layout::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
            if ret.layout.fields.count() == 1 {
                if let Some(reg) = float_reg(cx, ret, 0) {
                    ret.cast_to(reg);
                    return;
                }
            } else if ret.layout.fields.count() == 2 {
                if let Some(reg0) = float_reg(cx, ret, 0) {
                    if let Some(reg1) = float_reg(cx, ret, 1) {
                        ret.cast_to(CastTarget::Pair(reg0, reg1));
                        return;
                    }
                }
            }
        }

        // Cast to a uniform int structure
        ret.cast_to(Uniform {
            unit: bits_to_int_reg(bits),
            total: size
        });
    } else {
        ret.make_indirect();
    }
}

fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
    if !arg.layout.is_aggregate() {
        extend_integer_width_mips(arg, 64);
        return;
    }

    let dl = &cx.tcx.data_layout;
    let size = arg.layout.size;
    let mut prefix = [RegKind::Integer; 8];
    let mut prefix_index = 0;

    match arg.layout.fields {
        layout::FieldPlacement::Array { .. } => {
            // Arrays are passed indirectly
            arg.make_indirect();
            return;
        }
        layout::FieldPlacement::Union(_) => {
            // Unions and are always treated as a series of 64-bit integer chunks
        },
        layout::FieldPlacement::Arbitrary { .. } => {
            // Structures are split up into a series of 64-bit integer chunks, but any aligned
            // doubles not part of another aggregate are passed as floats.
            let mut last_offset = Size::from_bytes(0);

            for i in 0..arg.layout.fields.count() {
                let field = arg.layout.field(cx, i);
                let offset = arg.layout.fields.offset(i);

                // We only care about aligned doubles
                if let layout::Abi::Scalar(ref scalar) = field.abi {
                    if let layout::F64 = scalar.value {
                        if offset.is_abi_aligned(dl.f64_align) {
                            // Skip over enough integers to cover [last_offset, offset)
                            assert!(last_offset.is_abi_aligned(dl.f64_align));
                            prefix_index += ((offset - last_offset).bits() / 64) as usize;

                            if prefix_index >= prefix.len() {
                                break;
                            }

                            prefix[prefix_index] = RegKind::Float;
                            prefix_index += 1;
                            last_offset = offset + Reg::f64().size;
                        }
                    }
                }
            }
        }
    };

    // Extract first 8 chunks as the prefix
    arg.cast_to(CastTarget::ChunkedPrefix {
        prefix: prefix,
        chunk: Size::from_bytes(8),
        total: size
    });
}

pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
    if !fty.ret.is_ignore() {
        classify_ret_ty(cx, &mut fty.ret);
    }

    for arg in &mut fty.args {
        if arg.is_ignore() { continue; }
        classify_arg_ty(cx, arg);
    }
}
<|endoftext|>


<commit_before>// TODO: close events (port from old stdweb branch)
// TODO: pointer locking (stdweb PR required)
// TODO: fullscreen API (stdweb PR required)

mod device;
mod error;
mod event_loop;
mod monitor;
mod window;

#[cfg(feature = "web-sys")]
#[path = "web_sys/mod.rs"]
mod backend;

#[cfg(feature = "stdweb")]
#[path = "stdweb/mod.rs"]
mod backend;

#[cfg(not(any(feature = "web-sys", feature = "stdweb")))]
compile_error!("Please select a feature to build for web: `web-sys`, `stdweb`");

pub use self::device::Id as DeviceId;
pub use self::error::OsError;
pub use self::event_loop::{
    EventLoop, Proxy as EventLoopProxy, WindowTarget as EventLoopWindowTarget,
};
pub use self::monitor::{Handle as MonitorHandle, Mode as VideoMode};
pub use self::window::{
    Id as WindowId, PlatformSpecificBuilderAttributes as PlatformSpecificWindowBuilderAttributes,
    Window,
};
<commit_msg>Remove TODOs from the web backen (#1395)<commit_after>mod device;
mod error;
mod event_loop;
mod monitor;
mod window;

#[cfg(feature = "web-sys")]
#[path = "web_sys/mod.rs"]
mod backend;

#[cfg(feature = "stdweb")]
#[path = "stdweb/mod.rs"]
mod backend;

#[cfg(not(any(feature = "web-sys", feature = "stdweb")))]
compile_error!("Please select a feature to build for web: `web-sys`, `stdweb`");

pub use self::device::Id as DeviceId;
pub use self::error::OsError;
pub use self::event_loop::{
    EventLoop, Proxy as EventLoopProxy, WindowTarget as EventLoopWindowTarget,
};
pub use self::monitor::{Handle as MonitorHandle, Mode as VideoMode};
pub use self::window::{
    Id as WindowId, PlatformSpecificBuilderAttributes as PlatformSpecificWindowBuilderAttributes,
    Window,
};
<|endoftext|>


<commit_before>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, RequestExt, StatusCode};
use conduit_cookie::RequestSession;

use crate::middleware::response_timing::ResponseTime;
use std::fmt::{self, Display, Formatter};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

#[derive(Default)]
pub(super) struct LogRequests();

struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);

        if let Some(request_id) = req
            .headers()
            .get("x-request-id")
            .and_then(|value| value.to_str().ok())
        {
            sentry::configure_scope(|scope| scope.set_tag("request.id", request_id));
        }

        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        println!("{}", RequestLine { req, res: &res });

        report_to_sentry(req, &res);

        res
    }
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }

    sentry::configure_scope(|scope| scope.set_extra(key, value.to_string().into()));
}

fn report_to_sentry(req: &dyn RequestExt, res: &AfterResult) {
    sentry::configure_scope(|scope| {
        {
            let id = req.session().get("user_id").map(|str| str.to_string());

            let user = sentry::User {
                id,
                ..Default::default()
            };

            scope.set_user(Some(user));
        }

        {
            let status = res
                .as_ref()
                .map(|resp| resp.status())
                .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

            scope.set_tag("response.status", status.as_str());
        }

        if let Some(response_time) = req.extensions().find::<ResponseTime>() {
            scope.set_extra("Response time [ms]", response_time.as_millis().into());
        }
    });
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let status = self.res.as_ref().map(|res| res.status());
        let status = status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

        let at = if status.is_server_error() {
            "error"
        } else {
            "info"
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;

        // The request_id is not logged for successful download requests
        if !(self.req.path().ends_with("/download")
            && self
                .res
                .as_ref()
                .ok()
                .map(|ok| ok.status().is_redirection())
                == Some(true))
        {
            line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        }

        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;

        let response_time = self.req.extensions().find::<ResponseTime>();
        if let Some(response_time) = response_time {
            line.add_field("service", response_time)?;
        }
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if let Some(response_time) = response_time {
            if response_time.as_millis() > SLOW_REQUEST_THRESHOLD_MS {
                line.add_marker("SLOW REQUEST")?;
            }
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        write!(
            f,
            "{}",
            self.0.extensions().find::<OriginalPath>().unwrap().0
        )?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<commit_msg>middleware::log_request: Simplify `Display for FullPath` implementation<commit_after>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, RequestExt, StatusCode};
use conduit_cookie::RequestSession;

use crate::middleware::response_timing::ResponseTime;
use std::fmt::{self, Display, Formatter};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

#[derive(Default)]
pub(super) struct LogRequests();

struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);

        if let Some(request_id) = req
            .headers()
            .get("x-request-id")
            .and_then(|value| value.to_str().ok())
        {
            sentry::configure_scope(|scope| scope.set_tag("request.id", request_id));
        }

        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        println!("{}", RequestLine { req, res: &res });

        report_to_sentry(req, &res);

        res
    }
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }

    sentry::configure_scope(|scope| scope.set_extra(key, value.to_string().into()));
}

fn report_to_sentry(req: &dyn RequestExt, res: &AfterResult) {
    sentry::configure_scope(|scope| {
        {
            let id = req.session().get("user_id").map(|str| str.to_string());

            let user = sentry::User {
                id,
                ..Default::default()
            };

            scope.set_user(Some(user));
        }

        {
            let status = res
                .as_ref()
                .map(|resp| resp.status())
                .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

            scope.set_tag("response.status", status.as_str());
        }

        if let Some(response_time) = req.extensions().find::<ResponseTime>() {
            scope.set_extra("Response time [ms]", response_time.as_millis().into());
        }
    });
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let status = self.res.as_ref().map(|res| res.status());
        let status = status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

        let at = if status.is_server_error() {
            "error"
        } else {
            "info"
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;

        // The request_id is not logged for successful download requests
        if !(self.req.path().ends_with("/download")
            && self
                .res
                .as_ref()
                .ok()
                .map(|ok| ok.status().is_redirection())
                == Some(true))
        {
            line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        }

        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;

        let response_time = self.req.extensions().find::<ResponseTime>();
        if let Some(response_time) = response_time {
            line.add_field("service", response_time)?;
        }
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if let Some(response_time) = response_time {
            if response_time.as_millis() > SLOW_REQUEST_THRESHOLD_MS {
                line.add_marker("SLOW REQUEST")?;
            }
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let request = self.0;

        let original_path = request.extensions().find::<OriginalPath>();
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        let path = original_path.map(|p| p.0.as_str()).unwrap();

        write!(f, "{}", path)?;

        if let Some(q_string) = request.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::entities::*;
use crate::enums::*;
use crate::*;

use std::fs::{create_dir_all, read_to_string, remove_dir_all};
use std::path::Path;
use std::process::Command;
use std::thread::panicking;
use std::time::SystemTime;

extern crate glob;
use glob::glob;

struct Oda {
    temp_path: String,
    input_path: String,
    output_path: String,
    oda_path: String,
}

impl Drop for Oda {
    fn drop(&mut self) {
        if panicking() {
            println!("Test drawings at '{}'", self.temp_path);
        } else {
            remove_dir_all(Path::new(&self.temp_path)).unwrap();
        }
    }
}

impl Oda {
    pub fn convert_drawing(&self, drawing: &Drawing, version: AcadVersion) -> Drawing {
        drawing
            .save_file(&format!("{}/drawing.dxf", self.input_path))
            .unwrap();
        // e.g.,
        //   ODAFileConverter.exe input_dir output_dir ACAD2000 DXF 0 1
        let mut oda_convert = Command::new(&self.oda_path)
            .arg(&self.input_path)
            .arg(&self.output_path)
            .arg(&Oda::version_string(version))
            .arg("DXF")
            .arg("0") // recurse
            .arg("1") // audit
            .spawn()
            .expect("Failed to spawn ODA converter");
        let exit_code = oda_convert
            .wait()
            .expect("Failed to wait for ODA converter");
        let mut error_messages = String::from("");
        for entry in glob(format!("{}/*.err", &self.output_path).as_str())
            .expect("failed to glob for ODA error logs")
        {
            match entry {
                Ok(path) if path.is_file() => {
                    error_messages.push_str(format!("{}:\n", path.to_str().unwrap()).as_str());
                    let error_contents = read_to_string(path).unwrap();
                    error_messages.push_str(error_contents.as_str());
                    error_messages.push_str("\n\n");
                }
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if !error_messages.is_empty() {
            panic!(format!("Error converting files:\n{}", error_messages));
        }

        assert!(exit_code.success());
        Drawing::load_file(&format!("{}/drawing.dxf", self.output_path)).unwrap()
    }
    fn version_string(version: AcadVersion) -> String {
        let s = match version {
            AcadVersion::R9 => "ACAD9",
            AcadVersion::R10 => "ACAD10",
            AcadVersion::R12 => "ACAD12",
            AcadVersion::R13 => "ACAD13",
            AcadVersion::R14 => "ACAD14",
            AcadVersion::R2000 => "ACAD2000",
            AcadVersion::R2004 => "ACAD2004",
            AcadVersion::R2007 => "ACAD2007",
            AcadVersion::R2010 => "ACAD2010",
            AcadVersion::R2013 => "ACAD2013",
            _ => panic!("Unsupported ODA version {}", version),
        };
        String::from(s)
    }
}

macro_rules! require_oda {
    () => {{
        // Find ODA converter.  Final path looks something like:
        //   C:\Program Files\ODA\ODAFileConverter_title 20.12.0\ODAFileConverter.exe
        let mut full_oda_path = None;
        for entry in glob("C:/Program Files/ODA/ODAFileConverter*/ODAFileConverter.exe")
            .expect("failed to glob for ODA converter")
        {
            match entry {
                Ok(path) if path.is_file() => full_oda_path = Some(path),
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if full_oda_path == None {
            // didn't find ODA converter directory
            return;
        }
        let full_oda_path = full_oda_path.unwrap();

        // make and report temporary directory
        let nanos = format!(
            "{}",
            SystemTime::now()
                .duration_since(SystemTime::UNIX_EPOCH)
                .unwrap()
                .as_nanos()
        );
        let temp_path = format!("{}/integration-tests/{}", env!("OUT_DIR"), nanos);
        let input_path = format!("{}/input", temp_path);
        let output_path = format!("{}/output", temp_path);
        create_dir_all(Path::new(&temp_path)).unwrap();
        create_dir_all(Path::new(&input_path)).unwrap();
        create_dir_all(Path::new(&output_path)).unwrap();
        Oda {
            temp_path,
            input_path,
            output_path,
            oda_path: String::from(full_oda_path.to_str().unwrap()),
        }
    }};
}

#[test]
fn simple_line_can_be_read_by_oda() {
    let oda = require_oda!();
    let mut drawing = Drawing::new();
    drawing.add_entity(Entity {
        common: Default::default(),
        specific: EntityType::Line(Line {
            p1: Point::new(1.0, 2.0, 3.0),
            p2: Point::new(4.0, 5.0, 6.0),
            ..Default::default()
        }),
    });

    let round_tripped = oda.convert_drawing(&drawing, AcadVersion::R2000);
    let entities = round_tripped.entities().collect::<Vec<_>>();
    assert_eq!(1, entities.len());
    match entities[0].specific {
        EntityType::Line(ref line) => {
            assert_eq!(Point::new(1.0, 2.0, 3.0), line.p1);
            assert_eq!(Point::new(4.0, 5.0, 6.0), line.p2);
        }
        _ => panic!("expected a line"),
    }
}
<commit_msg>add another supported ODA version<commit_after>use crate::entities::*;
use crate::enums::*;
use crate::*;

use std::fs::{create_dir_all, read_to_string, remove_dir_all};
use std::path::Path;
use std::process::Command;
use std::thread::panicking;
use std::time::SystemTime;

extern crate glob;
use glob::glob;

struct Oda {
    temp_path: String,
    input_path: String,
    output_path: String,
    oda_path: String,
}

impl Drop for Oda {
    fn drop(&mut self) {
        if panicking() {
            println!("Test drawings at '{}'", self.temp_path);
        } else {
            remove_dir_all(Path::new(&self.temp_path)).unwrap();
        }
    }
}

impl Oda {
    pub fn convert_drawing(&self, drawing: &Drawing, version: AcadVersion) -> Drawing {
        drawing
            .save_file(&format!("{}/drawing.dxf", self.input_path))
            .unwrap();
        // e.g.,
        //   ODAFileConverter.exe input_dir output_dir ACAD2000 DXF 0 1
        let mut oda_convert = Command::new(&self.oda_path)
            .arg(&self.input_path)
            .arg(&self.output_path)
            .arg(&Oda::version_string(version))
            .arg("DXF")
            .arg("0") // recurse
            .arg("1") // audit
            .spawn()
            .expect("Failed to spawn ODA converter");
        let exit_code = oda_convert
            .wait()
            .expect("Failed to wait for ODA converter");
        let mut error_messages = String::from("");
        for entry in glob(format!("{}/*.err", &self.output_path).as_str())
            .expect("failed to glob for ODA error logs")
        {
            match entry {
                Ok(path) if path.is_file() => {
                    error_messages.push_str(format!("{}:\n", path.to_str().unwrap()).as_str());
                    let error_contents = read_to_string(path).unwrap();
                    error_messages.push_str(error_contents.as_str());
                    error_messages.push_str("\n\n");
                }
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if !error_messages.is_empty() {
            panic!(format!("Error converting files:\n{}", error_messages));
        }

        assert!(exit_code.success());
        Drawing::load_file(&format!("{}/drawing.dxf", self.output_path)).unwrap()
    }
    fn version_string(version: AcadVersion) -> String {
        let s = match version {
            AcadVersion::R9 => "ACAD9",
            AcadVersion::R10 => "ACAD10",
            AcadVersion::R12 => "ACAD12",
            AcadVersion::R13 => "ACAD13",
            AcadVersion::R14 => "ACAD14",
            AcadVersion::R2000 => "ACAD2000",
            AcadVersion::R2004 => "ACAD2004",
            AcadVersion::R2007 => "ACAD2007",
            AcadVersion::R2010 => "ACAD2010",
            AcadVersion::R2013 => "ACAD2013",
            AcadVersion::R2018 => "ACAD2018",
            _ => panic!("Unsupported ODA version {}", version),
        };
        String::from(s)
    }
}

macro_rules! require_oda {
    () => {{
        // Find ODA converter.  Final path looks something like:
        //   C:\Program Files\ODA\ODAFileConverter_title 20.12.0\ODAFileConverter.exe
        let mut full_oda_path = None;
        for entry in glob("C:/Program Files/ODA/ODAFileConverter*/ODAFileConverter.exe")
            .expect("failed to glob for ODA converter")
        {
            match entry {
                Ok(path) if path.is_file() => full_oda_path = Some(path),
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if full_oda_path == None {
            // didn't find ODA converter directory
            return;
        }
        let full_oda_path = full_oda_path.unwrap();

        // make and report temporary directory
        let nanos = format!(
            "{}",
            SystemTime::now()
                .duration_since(SystemTime::UNIX_EPOCH)
                .unwrap()
                .as_nanos()
        );
        let temp_path = format!("{}/integration-tests/{}", env!("OUT_DIR"), nanos);
        let input_path = format!("{}/input", temp_path);
        let output_path = format!("{}/output", temp_path);
        create_dir_all(Path::new(&temp_path)).unwrap();
        create_dir_all(Path::new(&input_path)).unwrap();
        create_dir_all(Path::new(&output_path)).unwrap();
        Oda {
            temp_path,
            input_path,
            output_path,
            oda_path: String::from(full_oda_path.to_str().unwrap()),
        }
    }};
}

#[test]
fn simple_line_can_be_read_by_oda() {
    let oda = require_oda!();
    let mut drawing = Drawing::new();
    drawing.add_entity(Entity {
        common: Default::default(),
        specific: EntityType::Line(Line {
            p1: Point::new(1.0, 2.0, 3.0),
            p2: Point::new(4.0, 5.0, 6.0),
            ..Default::default()
        }),
    });

    let round_tripped = oda.convert_drawing(&drawing, AcadVersion::R2000);
    let entities = round_tripped.entities().collect::<Vec<_>>();
    assert_eq!(1, entities.len());
    match entities[0].specific {
        EntityType::Line(ref line) => {
            assert_eq!(Point::new(1.0, 2.0, 3.0), line.p1);
            assert_eq!(Point::new(4.0, 5.0, 6.0), line.p2);
        }
        _ => panic!("expected a line"),
    }
}
<|endoftext|>


<commit_before>use crate::core::view::ScreenOverlayFilter;

use crate::core::view::LayoutEnv;

use super::mark::Mark;
use crate::core::codepointinfo::TextStyle;

use crate::core::screen::Screen;
use crate::core::view::View;

use super::TextModeContext;

use crate::core::screen::screen_apply;

pub struct DrawMarks {}

impl DrawMarks {
    pub fn new() -> Self {
        Self {}
    }
}

impl ScreenOverlayFilter<'_> for DrawMarks {
    fn name(&self) -> &'static str {
        &"DrawMarks"
    }

    fn finish(&mut self, view: &View, env: &mut LayoutEnv) {
        if env.screen.is_off_screen {
            return;
        }

        let tm = view.mode_ctx::<TextModeContext>("text-mode");
        let marks = &tm.marks;

        let _draw_marks = true;
        refresh_screen_marks(&mut env.screen, marks, true);
    }
}

pub fn refresh_screen_marks(screen: &mut Screen, marks: &Vec<Mark>, set: bool) {
    dbg_println!(
        "DRAW MARKS TRY DRAW OFFSET : FIRST {:?}  LAST {:?}",
        screen.first_offset,
        screen.last_offset
    );

    let idx_max = marks.len();

    if idx_max == 1 && !screen.contains_offset(marks[0].offset) {
        dbg_println!("MARK is offscreen");
        return;
    }

    if !set {
        screen_apply(screen, |_, _, cpi| {
            cpi.style.is_inverse = false;
            true // continue
        });
        return;
    }

    let (first_offset, last_offset) = match (screen.first_offset, screen.last_offset) {
        (Some(first_offset), Some(last_offset)) => (first_offset, last_offset),
        _ => {
            dbg_println!("CANNOT DRAW MARKS");
            return;
        }
    };

    let mut idx = 0;
    // get first on screen mark index
    while idx < idx_max {
        if marks[idx].offset < first_offset {
            idx += 1;
            continue;
        }
        break;
    }

    let mut lines_with_marks = vec![];
    if idx < idx_max && marks[idx].offset <= last_offset {
        screen_apply(screen, |_c, l, cpi| {
            if let Some(offset) = cpi.offset {
                // get next mark
                while idx < idx_max {
                    if marks[idx].offset >= offset {
                        break;
                    }
                    idx += 1;
                }
                if idx == idx_max {
                    return false;
                }
                if marks[idx].offset > last_offset {
                    return false;
                }

                // check offset
                if offset == marks[idx].offset {
                    cpi.style.is_inverse = true;

                    // save line index
                    let mut save_line = true;
                    if let Some(last) = lines_with_marks.last() {
                        save_line = *last != l;
                    }
                    if save_line {
                        lines_with_marks.push(l);
                    }
                }
            }

            true
        });
    }

    // highlight mark-line
    for l in lines_with_marks {
        if let Some(line) = screen.get_line_mut(l) {
            for cell in line {
                if !cell.cpi.style.is_selected {
                    // bg already changed ? (ex: trailing spaces)
                    if cell.cpi.style.bg_color == TextStyle::default_bg_color() {
                        cell.cpi.style.bg_color = TextStyle::default_mark_line_bg_color();
                    }
                }
            }
        }
    }
}
<commit_msg>do not highlight line with marks when the selection is active<commit_after>use crate::core::view::ScreenOverlayFilter;

use crate::core::view::LayoutEnv;

use super::mark::Mark;
use crate::core::codepointinfo::TextStyle;

use crate::core::screen::Screen;
use crate::core::view::View;

use super::TextModeContext;

use crate::core::screen::screen_apply;

pub struct DrawMarks {}

impl DrawMarks {
    pub fn new() -> Self {
        Self {}
    }
}

impl ScreenOverlayFilter<'_> for DrawMarks {
    fn name(&self) -> &'static str {
        &"DrawMarks"
    }

    fn finish(&mut self, view: &View, env: &mut LayoutEnv) {
        if env.screen.is_off_screen {
            return;
        }

        let tm = view.mode_ctx::<TextModeContext>("text-mode");

        let highlight_line_with_marks = tm.select_point.is_empty();
        let marks = &tm.marks;

        let _draw_marks = true;
        refresh_screen_marks(&mut env.screen, marks, true, highlight_line_with_marks);
    }
}

pub fn refresh_screen_marks(
    screen: &mut Screen,
    marks: &Vec<Mark>,
    set: bool,
    highlight_line_with_marks: bool,
) {
    dbg_println!(
        "DRAW MARKS TRY DRAW OFFSET : FIRST {:?}  LAST {:?}",
        screen.first_offset,
        screen.last_offset
    );

    let idx_max = marks.len();

    if idx_max == 1 && !screen.contains_offset(marks[0].offset) {
        dbg_println!("MARK is offscreen");
        return;
    }

    if !set {
        screen_apply(screen, |_, _, cpi| {
            cpi.style.is_inverse = false;
            true // continue
        });
        return;
    }

    let (first_offset, last_offset) = match (screen.first_offset, screen.last_offset) {
        (Some(first_offset), Some(last_offset)) => (first_offset, last_offset),
        _ => {
            dbg_println!("CANNOT DRAW MARKS");
            return;
        }
    };

    let mut idx = 0;
    // get first on screen mark index
    while idx < idx_max {
        if marks[idx].offset < first_offset {
            idx += 1;
            continue;
        }
        break;
    }

    let mut lines_with_marks = vec![];
    if idx < idx_max && marks[idx].offset <= last_offset {
        screen_apply(screen, |_c, l, cpi| {
            if let Some(offset) = cpi.offset {
                // get next mark
                while idx < idx_max {
                    if marks[idx].offset >= offset {
                        break;
                    }
                    idx += 1;
                }
                if idx == idx_max {
                    return false;
                }
                if marks[idx].offset > last_offset {
                    return false;
                }

                // check offset
                if offset == marks[idx].offset {
                    cpi.style.is_inverse = true;

                    // save line index
                    let mut save_line = true;
                    if let Some(last) = lines_with_marks.last() {
                        save_line = *last != l;
                    }
                    if save_line {
                        lines_with_marks.push(l);
                    }
                }
            }

            true
        });
    }

    // highlight mark-line
    if !highlight_line_with_marks {
        return;
    }

    for l in lines_with_marks {
        if let Some(line) = screen.get_line_mut(l) {
            for cell in line {
                if !cell.cpi.style.is_selected {
                    // bg already changed ? (ex: trailing spaces)
                    if cell.cpi.style.bg_color == TextStyle::default_bg_color() {
                        cell.cpi.style.bg_color = TextStyle::default_mark_line_bg_color();
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource_type::ResourceType;
use core::resource_manager::ResourceManager;

use std::fmt;
use std::fmt::{Formatter, Display};

use std::fs::{create_dir_all, File};

use std::io::Read;
use std::io::{Error, ErrorKind, Result};

use std::path::{Path, PathBuf};
use zip::read::ZipArchive;

#[derive(PartialEq, Eq, Hash)]
pub struct Resource {
    namespace: &'static str,
    resource_type: ResourceType,
    resource_path: Option<&'static str>,
    name: &'static str,
}

impl Display for Resource {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "[{}:{}:{}]", self.namespace, self.resource_type, self.name)
    }
}

impl Resource {
    pub fn new(namespace: &'static str, name: &'static str, resource_type: ResourceType) -> Resource {
        Resource {
            namespace,
            resource_type,
            resource_path: None,
            name,
        }
    }

    pub fn litecraft(name: &'static str, resource_type: ResourceType) -> Resource {
        Resource::new("litecraft", name, resource_type)
    }

    pub fn minecraft(name: &'static str, resource_type: ResourceType) -> Resource {
        Resource::new("minecraft", name, resource_type)
    }

    pub fn new_path(
        namespace: &'static str, name: &'static str, path: &'static str, r_type: ResourceType,
    ) -> Resource {
        Resource {
            namespace,
            resource_type: r_type,
            resource_path: Some(path),
            name,
        }
    }

    pub fn litecraft_path(
        name: &'static str, path: &'static str, resource_type: ResourceType,
    ) -> Resource {
        Resource::new_path("litecraft", name, path, resource_type)
    }

    pub fn minecraft_path(
        name: &'static str, path: &'static str, resource_type: ResourceType,
    ) -> Resource {
        Resource::new_path("minecraft", name, path, resource_type)
    }

    pub fn folder(&self, parent: &str) -> String {
        if let Some(ref resource_path) = self.resource_path {
            format!(
                "{}/{}/{}/{}/{}.{}",
                parent,                         // Ex. resources
                self.namespace,                 // Ex. minecraft
                self.resource_type.folder(),    // Ex. textures
                resource_path,                  // Ex. entity
                self.name,                      // Ex. creeper
                self.resource_type.extension(), // Ex. png
            )
        } else {
            format!(
                "{}/{}/{}/{}.{}",
                parent,                         // Ex. assets
                self.namespace,                 // Ex. litecraft
                self.resource_type.folder(),    // Ex. textures
                self.name,                      // Ex. logo
                self.resource_type.extension(), // Ex. png
            )
        }
    }

    /// Get most priority file to load
    fn find(&self) -> Result<Vec<u8>> {
        if !Path::new("resourcepacks").exists() {
            create_dir_all("resourcepacks")?;
        }

        let resourcepacks = ResourceManager::resourcepacks();

        // Get all enabled resource packs
        let resourcepacks = resourcepacks
            .into_iter()
            .map(|entry| {
                let mut path = PathBuf::from("resourcepacks");
                path.push(entry);
                path
            }).filter(|entry| entry.exists())
            .filter(|entry| entry.is_file());

        // Check every resourcepack
        for entry in resourcepacks {
            // Read resourcepack ZIP file
            let zipfile = File::open(entry)?;
            let mut zipfile = ZipArchive::new(zipfile)?;

            // Read resource from ZIP
            let mut file = zipfile.by_name(&self.folder("assets"));

            // If file exist in zip
            if let Ok(mut file) = file {
                let mut buffer = Vec::new();
                file.read_to_end(&mut buffer)?;

                return Ok(buffer);
            }
        }

        // Nothing found on any resource pack, using resources folder now...
        let path = self.folder("resources");
        let path = Path::new(&path);

        if path.exists() {
            let mut file = File::open(path)?;
            let mut buffer = Vec::new();

            file.read_to_end(&mut buffer)?;
            return Ok(buffer);
        }

        Err(Error::new(
            ErrorKind::Other,
            format!("Resource {} does not exist on any resource pack", self),
        ))
    }

    /// Get a resource as plain test
    pub fn load(&self) -> String {
        String::from_utf8(self.load_binary()).expect("Failed to decode required resource as UTF-8 text")
    }

    /// Get a resource as binary
    pub fn load_binary(&self) -> Vec<u8> {
        self.find().expect("Failed to load required binary resource")
    }
}
<commit_msg>Reformat code<commit_after>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource_type::ResourceType;
use core::resource_manager::ResourceManager;

use std::fmt;
use std::fmt::{Display, Formatter};

use std::fs::{create_dir_all, File};

use std::io::Read;
use std::io::{Error, ErrorKind, Result};

use std::path::{Path, PathBuf};
use zip::read::ZipArchive;

#[derive(PartialEq, Eq, Hash)]
pub struct Resource {
    namespace: &'static str,
    resource_type: ResourceType,
    resource_path: Option<&'static str>,
    name: &'static str,
}

impl Display for Resource {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "[{}:{}:{}]", self.namespace, self.resource_type, self.name)
    }
}

impl Resource {
    pub fn new(namespace: &'static str, name: &'static str, resource_type: ResourceType) -> Resource {
        Resource {
            namespace,
            resource_type,
            resource_path: None,
            name,
        }
    }

    pub fn litecraft(name: &'static str, resource_type: ResourceType) -> Resource {
        Resource::new("litecraft", name, resource_type)
    }

    pub fn minecraft(name: &'static str, resource_type: ResourceType) -> Resource {
        Resource::new("minecraft", name, resource_type)
    }

    pub fn new_path(
        namespace: &'static str, name: &'static str, path: &'static str, r_type: ResourceType,
    ) -> Resource {
        Resource {
            namespace,
            resource_type: r_type,
            resource_path: Some(path),
            name,
        }
    }

    pub fn litecraft_path(
        name: &'static str, path: &'static str, resource_type: ResourceType,
    ) -> Resource {
        Resource::new_path("litecraft", name, path, resource_type)
    }

    pub fn minecraft_path(
        name: &'static str, path: &'static str, resource_type: ResourceType,
    ) -> Resource {
        Resource::new_path("minecraft", name, path, resource_type)
    }

    pub fn folder(&self, parent: &str) -> String {
        if let Some(ref resource_path) = self.resource_path {
            format!(
                "{}/{}/{}/{}/{}.{}",
                parent,                         // Ex. resources
                self.namespace,                 // Ex. minecraft
                self.resource_type.folder(),    // Ex. textures
                resource_path,                  // Ex. entity
                self.name,                      // Ex. creeper
                self.resource_type.extension(), // Ex. png
            )
        } else {
            format!(
                "{}/{}/{}/{}.{}",
                parent,                         // Ex. assets
                self.namespace,                 // Ex. litecraft
                self.resource_type.folder(),    // Ex. textures
                self.name,                      // Ex. logo
                self.resource_type.extension(), // Ex. png
            )
        }
    }

    /// Get most priority file to load
    fn find(&self) -> Result<Vec<u8>> {
        if !Path::new("resourcepacks").exists() {
            create_dir_all("resourcepacks")?;
        }

        let resourcepacks = ResourceManager::resourcepacks();

        // Get all enabled resource packs
        let resourcepacks = resourcepacks
            .into_iter()
            .map(|entry| {
                let mut path = PathBuf::from("resourcepacks");
                path.push(entry);
                path
            }).filter(|entry| entry.exists())
            .filter(|entry| entry.is_file());

        // Check every resourcepack
        for entry in resourcepacks {
            // Read resourcepack ZIP file
            let zipfile = File::open(entry)?;
            let mut zipfile = ZipArchive::new(zipfile)?;

            // Read resource from ZIP
            let mut file = zipfile.by_name(&self.folder("assets"));

            // If file exist in zip
            if let Ok(mut file) = file {
                let mut buffer = Vec::new();
                file.read_to_end(&mut buffer)?;

                return Ok(buffer);
            }
        }

        // Nothing found on any resource pack, using resources folder now...
        let path = self.folder("resources");
        let path = Path::new(&path);

        if path.exists() {
            let mut file = File::open(path)?;
            let mut buffer = Vec::new();

            file.read_to_end(&mut buffer)?;
            return Ok(buffer);
        }

        Err(Error::new(
            ErrorKind::Other,
            format!("Resource {} does not exist on any resource pack", self),
        ))
    }

    /// Get a resource as plain test
    pub fn load(&self) -> String {
        String::from_utf8(self.load_binary()).expect("Failed to decode required resource as UTF-8 text")
    }

    /// Get a resource as binary
    pub fn load_binary(&self) -> Vec<u8> {
        self.find().expect("Failed to load required binary resource")
    }
}
<|endoftext|>