<commit_before>use std::env;
use std::ffi::OsString;
use std::fs::{self, File, OpenOptions, Permissions};
use std::io::{Read, Result, Write};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};

#[cfg(feature = "temp")]
use tempdir;

use {DirEntry, FileSystem, ReadDir};
#[cfg(feature = "temp")]
use {TempDir, TempFileSystem};
#[cfg(unix)]
use UnixFileSystem;

/// Tracks a temporary directory that will be deleted once the struct goes out of scope.
///
/// This is a wrapper around a [`TempDir`].
///
/// [`TempDir`]: https://doc.rust-lang.org/tempdir/tempdir/struct.TempDir.html
#[cfg(feature = "temp")]
#[derive(Debug)]
pub struct OsTempDir(tempdir::TempDir);

#[cfg(feature = "temp")]
impl TempDir for OsTempDir {
    fn path(&self) -> &Path {
        self.0.path()
    }
}

/// An implementation of `FileSystem` that interacts with the actual operating system's file system.
///
/// This is primarily a wrapper for [`fs`] methods.
///
/// [`fs`]: https://doc.rust-lang.org/std/fs/index.html
#[derive(Clone, Debug, Default)]
pub struct OsFileSystem {}

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

impl FileSystem for OsFileSystem {
    type DirEntry = fs::DirEntry;
    type ReadDir = fs::ReadDir;

    fn current_dir(&self) -> Result<PathBuf> {
        env::current_dir()
    }

    fn set_current_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        env::set_current_dir(path)
    }

    fn is_dir<P: AsRef<Path>>(&self, path: P) -> bool {
        path.as_ref().is_dir()
    }

    fn is_file<P: AsRef<Path>>(&self, path: P) -> bool {
        path.as_ref().is_file()
    }

    fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::create_dir(path)
    }

    fn create_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::create_dir_all(path)
    }

    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::remove_dir(path)
    }

    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::remove_dir_all(path)
    }

    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir> {
        fs::read_dir(path)
    }

    fn write_file<P, B>(&self, path: P, buf: B) -> Result<()>
    where
        P: AsRef<Path>,
        B: AsRef<[u8]>,
    {
        let mut file = File::create(path)?;
        file.write_all(buf.as_ref())
    }

    fn overwrite_file<P, B>(&self, path: P, buf: B) -> Result<()>
    where
        P: AsRef<Path>,
        B: AsRef<[u8]>,
    {
        let mut file = OpenOptions::new().write(true).open(path)?;
        file.write_all(buf.as_ref())
    }

    fn read_file<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>> {
        let mut contents = Vec::<u8>::new();
        let mut file = File::open(path)?;

        file.read_to_end(&mut contents)?;

        Ok(contents)
    }

    fn read_file_to_string<P: AsRef<Path>>(&self, path: P) -> Result<String> {
        let mut contents = String::new();
        let mut file = File::open(path)?;

        file.read_to_string(&mut contents)?;

        Ok(contents)
    }

    fn create_file<P, B>(&self, path: P, buf: B) -> Result<()>
    where
        P: AsRef<Path>,
        B: AsRef<[u8]>,
    {
        let mut file = OpenOptions::new().write(true).create_new(true).open(path)?;

        file.write_all(buf.as_ref())
    }

    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::remove_file(path)
    }

    fn copy_file<P, Q>(&self, from: P, to: Q) -> Result<()>
    where
        P: AsRef<Path>,
        Q: AsRef<Path>,
    {
        fs::copy(from, to).and(Ok(()))
    }

    fn rename<P, Q>(&self, from: P, to: Q) -> Result<()>
    where
        P: AsRef<Path>,
        Q: AsRef<Path>,
    {
        fs::rename(from, to)
    }

    fn readonly<P: AsRef<Path>>(&self, path: P) -> Result<bool> {
        permissions(path.as_ref()).map(|p| p.readonly())
    }

    fn set_readonly<P: AsRef<Path>>(&self, path: P, readonly: bool) -> Result<()> {
        let mut permissions = permissions(path.as_ref())?;

        permissions.set_readonly(readonly);

        fs::set_permissions(path, permissions)
    }
}

#[cfg(unix)]
impl UnixFileSystem for OsFileSystem {
    fn mode<P: AsRef<Path>>(&self, path: P) -> Result<u32> {
        permissions(path.as_ref()).map(|p| p.mode())
    }

    fn set_mode<P: AsRef<Path>>(&self, path: P, mode: u32) -> Result<()> {
        let mut permissions = permissions(path.as_ref())?;

        permissions.set_mode(mode);

        fs::set_permissions(path, permissions)
    }
}

#[cfg(feature = "temp")]
impl TempFileSystem for OsFileSystem {
    type TempDir = OsTempDir;

    fn temp_dir<S: AsRef<str>>(&self, prefix: S) -> Result<Self::TempDir> {
        tempdir::TempDir::new(prefix.as_ref()).map(OsTempDir)
    }
}

impl DirEntry for fs::DirEntry {
    fn file_name(&self) -> OsString {
        self.file_name()
    }

    fn path(&self) -> PathBuf {
        self.path()
    }
}

impl ReadDir<fs::DirEntry> for fs::ReadDir {}

fn permissions(path: &Path) -> Result<Permissions> {
    let metadata = fs::metadata(path)?;

    Ok(metadata.permissions())
}
<commit_msg>Truncate file when overwriting<commit_after>use std::env;
use std::ffi::OsString;
use std::fs::{self, File, OpenOptions, Permissions};
use std::io::{Read, Result, Write};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};

#[cfg(feature = "temp")]
use tempdir;

use {DirEntry, FileSystem, ReadDir};
#[cfg(feature = "temp")]
use {TempDir, TempFileSystem};
#[cfg(unix)]
use UnixFileSystem;

/// Tracks a temporary directory that will be deleted once the struct goes out of scope.
///
/// This is a wrapper around a [`TempDir`].
///
/// [`TempDir`]: https://doc.rust-lang.org/tempdir/tempdir/struct.TempDir.html
#[cfg(feature = "temp")]
#[derive(Debug)]
pub struct OsTempDir(tempdir::TempDir);

#[cfg(feature = "temp")]
impl TempDir for OsTempDir {
    fn path(&self) -> &Path {
        self.0.path()
    }
}

/// An implementation of `FileSystem` that interacts with the actual operating system's file system.
///
/// This is primarily a wrapper for [`fs`] methods.
///
/// [`fs`]: https://doc.rust-lang.org/std/fs/index.html
#[derive(Clone, Debug, Default)]
pub struct OsFileSystem {}

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

impl FileSystem for OsFileSystem {
    type DirEntry = fs::DirEntry;
    type ReadDir = fs::ReadDir;

    fn current_dir(&self) -> Result<PathBuf> {
        env::current_dir()
    }

    fn set_current_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        env::set_current_dir(path)
    }

    fn is_dir<P: AsRef<Path>>(&self, path: P) -> bool {
        path.as_ref().is_dir()
    }

    fn is_file<P: AsRef<Path>>(&self, path: P) -> bool {
        path.as_ref().is_file()
    }

    fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::create_dir(path)
    }

    fn create_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::create_dir_all(path)
    }

    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::remove_dir(path)
    }

    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::remove_dir_all(path)
    }

    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir> {
        fs::read_dir(path)
    }

    fn write_file<P, B>(&self, path: P, buf: B) -> Result<()>
    where
        P: AsRef<Path>,
        B: AsRef<[u8]>,
    {
        let mut file = File::create(path)?;
        file.write_all(buf.as_ref())
    }

    fn overwrite_file<P, B>(&self, path: P, buf: B) -> Result<()>
    where
        P: AsRef<Path>,
        B: AsRef<[u8]>,
    {
        let mut file = OpenOptions::new().write(true).truncate(true).open(path)?;
        file.write_all(buf.as_ref())
    }

    fn read_file<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>> {
        let mut contents = Vec::<u8>::new();
        let mut file = File::open(path)?;

        file.read_to_end(&mut contents)?;

        Ok(contents)
    }

    fn read_file_to_string<P: AsRef<Path>>(&self, path: P) -> Result<String> {
        let mut contents = String::new();
        let mut file = File::open(path)?;

        file.read_to_string(&mut contents)?;

        Ok(contents)
    }

    fn create_file<P, B>(&self, path: P, buf: B) -> Result<()>
    where
        P: AsRef<Path>,
        B: AsRef<[u8]>,
    {
        let mut file = OpenOptions::new().write(true).create_new(true).open(path)?;

        file.write_all(buf.as_ref())
    }

    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        fs::remove_file(path)
    }

    fn copy_file<P, Q>(&self, from: P, to: Q) -> Result<()>
    where
        P: AsRef<Path>,
        Q: AsRef<Path>,
    {
        fs::copy(from, to).and(Ok(()))
    }

    fn rename<P, Q>(&self, from: P, to: Q) -> Result<()>
    where
        P: AsRef<Path>,
        Q: AsRef<Path>,
    {
        fs::rename(from, to)
    }

    fn readonly<P: AsRef<Path>>(&self, path: P) -> Result<bool> {
        permissions(path.as_ref()).map(|p| p.readonly())
    }

    fn set_readonly<P: AsRef<Path>>(&self, path: P, readonly: bool) -> Result<()> {
        let mut permissions = permissions(path.as_ref())?;

        permissions.set_readonly(readonly);

        fs::set_permissions(path, permissions)
    }
}

#[cfg(unix)]
impl UnixFileSystem for OsFileSystem {
    fn mode<P: AsRef<Path>>(&self, path: P) -> Result<u32> {
        permissions(path.as_ref()).map(|p| p.mode())
    }

    fn set_mode<P: AsRef<Path>>(&self, path: P, mode: u32) -> Result<()> {
        let mut permissions = permissions(path.as_ref())?;

        permissions.set_mode(mode);

        fs::set_permissions(path, permissions)
    }
}

#[cfg(feature = "temp")]
impl TempFileSystem for OsFileSystem {
    type TempDir = OsTempDir;

    fn temp_dir<S: AsRef<str>>(&self, prefix: S) -> Result<Self::TempDir> {
        tempdir::TempDir::new(prefix.as_ref()).map(OsTempDir)
    }
}

impl DirEntry for fs::DirEntry {
    fn file_name(&self) -> OsString {
        self.file_name()
    }

    fn path(&self) -> PathBuf {
        self.path()
    }
}

impl ReadDir<fs::DirEntry> for fs::ReadDir {}

fn permissions(path: &Path) -> Result<Permissions> {
    let metadata = fs::metadata(path)?;

    Ok(metadata.permissions())
}
<|endoftext|>


<commit_before>// Copyright 2018-2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ffi::{CStr, CString};
use std::fmt;
use std::io;
use std::mem;
use std::ops::Deref;
use std::path::Path;
use std::ptr;

use enums::PsLevel;
use ffi;
use surface::Surface;

#[cfg(feature = "use_glib")]
use glib::translate::*;

impl PsLevel {
    pub fn as_str(self) -> Option<&'static str> {
        unsafe {
            let res = ffi::cairo_ps_level_to_string(self.into());
            res.as_ref()
                .and_then(|cstr| CStr::from_ptr(cstr as _).to_str().ok())
        }
    }
}

#[derive(Debug)]
pub struct PsSurface {
    inner: Surface,
}

#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for PsSurface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        let stash = self.inner.to_glib_none();
        Stash(stash.0, stash.1)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for PsSurface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> PsSurface {
        PsSurface {
            inner: from_glib_none(ptr),
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for PsSurface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> PsSurface {
        PsSurface {
            inner: from_glib_borrow(ptr),
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for PsSurface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> PsSurface {
        PsSurface {
            inner: Surface::from_raw_full(ptr),
        }
    }
}

impl PsSurface {
    pub fn new<P: AsRef<Path>>(width: f64, height: f64, path: P) -> Self {
        let path = path.as_ref().to_string_lossy().into_owned();
        let path = CString::new(path).unwrap();

        unsafe {
            Self {
                inner: Surface::from_raw_full(ffi::cairo_ps_surface_create(
                    path.as_ptr(),
                    width,
                    height,
                )),
            }
        }
    }

    for_stream_constructors!(cairo_ps_surface_create_for_stream);

    pub fn get_levels() -> impl Iterator<Item = PsLevel> {
        let lvls_slice = unsafe {
            let mut vers_ptr = ptr::null_mut();
            let mut num_vers = mem::MaybeUninit::uninit();
            ffi::cairo_ps_get_levels(&mut vers_ptr, num_vers.as_mut_ptr());

            std::slice::from_raw_parts(vers_ptr, num_vers.assume_init() as _)
        };

        lvls_slice.iter().map(|v| PsLevel::from(*v))
    }

    pub fn restrict(&self, level: PsLevel) {
        unsafe {
            ffi::cairo_ps_surface_restrict_to_level(self.inner.to_raw_none(), level.into());
        }
    }

    pub fn get_eps(&self) -> bool {
        unsafe { ffi::cairo_ps_surface_get_eps(self.inner.to_raw_none()).as_bool() }
    }

    pub fn set_eps(&self, eps: bool) {
        unsafe {
            ffi::cairo_ps_surface_set_eps(self.inner.to_raw_none(), eps.into());
        }
    }

    pub fn set_size(&self, width: f64, height: f64) {
        unsafe {
            ffi::cairo_ps_surface_set_size(self.inner.to_raw_none(), width, height);
        }
    }

    pub fn cairo_ps_surface_dsc_begin_setup(&self) {
        unsafe {
            ffi::cairo_ps_surface_dsc_begin_setup(self.inner.to_raw_none());
        }
    }

    pub fn cairo_ps_surface_dsc_begin_page_setup(&self) {
        unsafe {
            ffi::cairo_ps_surface_dsc_begin_page_setup(self.inner.to_raw_none());
        }
    }

    pub fn cairo_ps_surface_dsc_comment(&self, comment: &str) {
        let comment = CString::new(comment).unwrap();
        unsafe {
            ffi::cairo_ps_surface_dsc_comment(self.inner.to_raw_none(), comment.as_ptr());
        }
    }
}

impl Deref for PsSurface {
    type Target = Surface;

    fn deref(&self) -> &Surface {
        &self.inner
    }
}

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

#[cfg(test)]
mod test {
    use super::*;
    use context::*;
    use tempfile::tempfile;

    fn draw(surface: &Surface) {
        let cr = Context::new(surface);

        // Note: Not using RGBA here as PS doesn't natively support
        // semi-transparency and Cairo would then embed a rasterized bitmap

        cr.set_line_width(25.0);

        cr.set_source_rgb(1.0, 0.0, 0.0);
        cr.line_to(0., 0.);
        cr.line_to(100., 100.);
        cr.stroke();

        cr.set_source_rgb(0.0, 0.0, 1.0);
        cr.line_to(0., 100.);
        cr.line_to(100., 0.);
        cr.stroke();
    }

    fn draw_in_buffer() -> Vec<u8> {
        let buffer: Vec<u8> = vec![];

        let surface = PsSurface::for_stream(100., 100., buffer);
        draw(&surface);
        *surface.finish_output_stream().unwrap().downcast().unwrap()
    }

    #[test]
    fn levels() {
        assert!(PsSurface::get_levels().any(|v| v == PsLevel::_2));
    }

    #[test]
    fn level_string() {
        let ver_str = PsLevel::_2.as_str().unwrap();
        assert_eq!(ver_str, "PS Level 2");
    }

    #[test]
    fn eps() {
        let buffer: Vec<u8> = vec![];
        let surface = PsSurface::for_stream(100., 100., buffer);
        surface.set_eps(true);
        assert_eq!(surface.get_eps(), true);
    }

    #[test]
    #[cfg(unix)]
    fn file() {
        let surface = PsSurface::new(100., 100., "/dev/null");
        draw(&surface);
        surface.finish();
    }

    #[test]
    fn writer() {
        let file = tempfile().expect("tempfile failed");
        let surface = PsSurface::for_stream(100., 100., file);

        draw(&surface);
        let stream = surface.finish_output_stream().unwrap();
        let file = stream.downcast::<std::fs::File>().unwrap();

        let buffer = draw_in_buffer();
        let file_size = file.metadata().unwrap().len();
        assert_eq!(file_size, buffer.len() as u64);
    }

    #[test]
    fn ref_writer() {
        let mut file = tempfile().expect("tempfile failed");
        let surface = unsafe { PsSurface::for_raw_stream(100., 100., &mut file) };

        draw(&surface);
        surface.finish_output_stream().unwrap();
    }

    #[test]
    fn buffer() {
        let buffer = draw_in_buffer();

        let header = b"%!PS-Adobe";
        assert_eq!(&buffer[..header.len()], header);
    }

    #[test]
    fn custom_writer() {
        struct CustomWriter(usize);

        impl io::Write for CustomWriter {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.0 += buf.len();
                Ok(buf.len())
            }

            fn flush(&mut self) -> io::Result<()> {
                Ok(())
            }
        }

        let custom_writer = CustomWriter(0);

        let surface = PsSurface::for_stream(20., 20., custom_writer);
        surface.set_size(100., 100.);
        draw(&surface);
        let stream = surface.finish_output_stream().unwrap();
        let custom_writer = stream.downcast::<CustomWriter>().unwrap();

        let buffer = draw_in_buffer();

        assert_eq!(custom_writer.0, buffer.len());
    }

    fn with_panicky_stream() -> PsSurface {
        struct PanicWriter;

        impl io::Write for PanicWriter {
            fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
                panic!("panic in writer");
            }
            fn flush(&mut self) -> io::Result<()> {
                Ok(())
            }
        }

        let surface = PsSurface::for_stream(20., 20., PanicWriter);
        surface.finish();
        surface
    }

    #[test]
    #[should_panic]
    fn finish_stream_propagates_panic() {
        let _ = with_panicky_stream().finish_output_stream();
    }
}
<commit_msg>Add PsSurface::try_from(Surface)<commit_after>// Copyright 2018-2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::convert::TryFrom;
use std::ffi::{CStr, CString};
use std::fmt;
use std::io;
use std::mem;
use std::ops::Deref;
use std::path::Path;
use std::ptr;

use enums::{PsLevel, SurfaceType};
use ffi;
use surface::Surface;

#[cfg(feature = "use_glib")]
use glib::translate::*;

use Status;

impl PsLevel {
    pub fn as_str(self) -> Option<&'static str> {
        unsafe {
            let res = ffi::cairo_ps_level_to_string(self.into());
            res.as_ref()
                .and_then(|cstr| CStr::from_ptr(cstr as _).to_str().ok())
        }
    }
}

#[derive(Debug)]
pub struct PsSurface {
    inner: Surface,
}

impl TryFrom<Surface> for PsSurface {
    type Error = Surface;

    fn try_from(surface: Surface) -> Result<PsSurface, Surface> {
        if surface.get_type() == SurfaceType::Ps {
            Ok(PsSurface { inner: surface })
        } else {
            Err(surface)
        }
    }
}
#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for PsSurface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        let stash = self.inner.to_glib_none();
        Stash(stash.0, stash.1)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for PsSurface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> PsSurface {
        Self::try_from(from_glib_none::<_, Surface>(ptr)).unwrap()
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for PsSurface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> PsSurface {
        Self::try_from(from_glib_borrow::<_, Surface>(ptr)).unwrap()
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for PsSurface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> PsSurface {
        Self::from_raw_full(ptr).unwrap()
    }
}

impl PsSurface {
    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Result<PsSurface, Status> {
        let surface = Surface::from_raw_full(ptr)?;
        Self::try_from(surface).map_err(|_| Status::SurfaceTypeMismatch)
    }

    pub fn new<P: AsRef<Path>>(width: f64, height: f64, path: P) -> Result<PsSurface, Status> {
        let path = path.as_ref().to_string_lossy().into_owned();
        let path = CString::new(path).unwrap();

        unsafe {
            Self::from_raw_full(ffi::cairo_ps_surface_create(
                path.as_ptr(),
                width,
                height,
            ))
        }
    }

    for_stream_constructors!(cairo_ps_surface_create_for_stream);

    pub fn get_levels() -> impl Iterator<Item = PsLevel> {
        let lvls_slice = unsafe {
            let mut vers_ptr = ptr::null_mut();
            let mut num_vers = mem::MaybeUninit::uninit();
            ffi::cairo_ps_get_levels(&mut vers_ptr, num_vers.as_mut_ptr());

            std::slice::from_raw_parts(vers_ptr, num_vers.assume_init() as _)
        };

        lvls_slice.iter().map(|v| PsLevel::from(*v))
    }

    pub fn restrict(&self, level: PsLevel) {
        unsafe {
            ffi::cairo_ps_surface_restrict_to_level(self.inner.to_raw_none(), level.into());
        }
    }

    pub fn get_eps(&self) -> bool {
        unsafe { ffi::cairo_ps_surface_get_eps(self.inner.to_raw_none()).as_bool() }
    }

    pub fn set_eps(&self, eps: bool) {
        unsafe {
            ffi::cairo_ps_surface_set_eps(self.inner.to_raw_none(), eps.into());
        }
    }

    pub fn set_size(&self, width: f64, height: f64) {
        unsafe {
            ffi::cairo_ps_surface_set_size(self.inner.to_raw_none(), width, height);
        }
    }

    pub fn cairo_ps_surface_dsc_begin_setup(&self) {
        unsafe {
            ffi::cairo_ps_surface_dsc_begin_setup(self.inner.to_raw_none());
        }
    }

    pub fn cairo_ps_surface_dsc_begin_page_setup(&self) {
        unsafe {
            ffi::cairo_ps_surface_dsc_begin_page_setup(self.inner.to_raw_none());
        }
    }

    pub fn cairo_ps_surface_dsc_comment(&self, comment: &str) {
        let comment = CString::new(comment).unwrap();
        unsafe {
            ffi::cairo_ps_surface_dsc_comment(self.inner.to_raw_none(), comment.as_ptr());
        }
    }
}

impl Deref for PsSurface {
    type Target = Surface;

    fn deref(&self) -> &Surface {
        &self.inner
    }
}

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

#[cfg(test)]
mod test {
    use super::*;
    use context::*;
    use tempfile::tempfile;

    fn draw(surface: &Surface) {
        let cr = Context::new(surface);

        // Note: Not using RGBA here as PS doesn't natively support
        // semi-transparency and Cairo would then embed a rasterized bitmap

        cr.set_line_width(25.0);

        cr.set_source_rgb(1.0, 0.0, 0.0);
        cr.line_to(0., 0.);
        cr.line_to(100., 100.);
        cr.stroke();

        cr.set_source_rgb(0.0, 0.0, 1.0);
        cr.line_to(0., 100.);
        cr.line_to(100., 0.);
        cr.stroke();
    }

    fn draw_in_buffer() -> Vec<u8> {
        let buffer: Vec<u8> = vec![];

        let surface = PsSurface::for_stream(100., 100., buffer).unwrap();
        draw(&surface);
        *surface.finish_output_stream().unwrap().downcast().unwrap()
    }

    #[test]
    fn levels() {
        assert!(PsSurface::get_levels().any(|v| v == PsLevel::_2));
    }

    #[test]
    fn level_string() {
        let ver_str = PsLevel::_2.as_str().unwrap();
        assert_eq!(ver_str, "PS Level 2");
    }

    #[test]
    fn eps() {
        let buffer: Vec<u8> = vec![];
        let surface = PsSurface::for_stream(100., 100., buffer).unwrap();
        surface.set_eps(true);
        assert_eq!(surface.get_eps(), true);
    }

    #[test]
    #[cfg(unix)]
    fn file() {
        let surface = PsSurface::new(100., 100., "/dev/null").unwrap();
        draw(&surface);
        surface.finish();
    }

    #[test]
    fn writer() {
        let file = tempfile().expect("tempfile failed");
        let surface = PsSurface::for_stream(100., 100., file).unwrap();

        draw(&surface);
        let stream = surface.finish_output_stream().unwrap();
        let file = stream.downcast::<std::fs::File>().unwrap();

        let buffer = draw_in_buffer();
        let file_size = file.metadata().unwrap().len();
        assert_eq!(file_size, buffer.len() as u64);
    }

    #[test]
    fn ref_writer() {
        let mut file = tempfile().expect("tempfile failed");
        let surface = unsafe { PsSurface::for_raw_stream(100., 100., &mut file).unwrap() };

        draw(&surface);
        surface.finish_output_stream().unwrap();
    }

    #[test]
    fn buffer() {
        let buffer = draw_in_buffer();

        let header = b"%!PS-Adobe";
        assert_eq!(&buffer[..header.len()], header);
    }

    #[test]
    fn custom_writer() {
        struct CustomWriter(usize);

        impl io::Write for CustomWriter {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.0 += buf.len();
                Ok(buf.len())
            }

            fn flush(&mut self) -> io::Result<()> {
                Ok(())
            }
        }

        let custom_writer = CustomWriter(0);

        let surface = PsSurface::for_stream(20., 20., custom_writer).unwrap();
        surface.set_size(100., 100.);
        draw(&surface);
        let stream = surface.finish_output_stream().unwrap();
        let custom_writer = stream.downcast::<CustomWriter>().unwrap();

        let buffer = draw_in_buffer();

        assert_eq!(custom_writer.0, buffer.len());
    }

    fn with_panicky_stream() -> PsSurface {
        struct PanicWriter;

        impl io::Write for PanicWriter {
            fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
                panic!("panic in writer");
            }
            fn flush(&mut self) -> io::Result<()> {
                Ok(())
            }
        }

        let surface = PsSurface::for_stream(20., 20., PanicWriter).unwrap();
        surface.finish();
        surface
    }

    #[test]
    #[should_panic]
    fn finish_stream_propagates_panic() {
        let _ = with_panicky_stream().finish_output_stream();
    }
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg, SubCommand};

fn main() {
    // Test version from Cargo.toml
    let version = format!("{}.{}.{}{}",
                          env!("CARGO_PKG_VERSION_MAJOR"),
                          env!("CARGO_PKG_VERSION_MINOR"),
                          env!("CARGO_PKG_VERSION_PATCH"),
                          option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
    let matches = App::new("claptests")
                        .version(&version[..])
                        .about("tests clap library")
                        .author("Kevin K. <kbknapp@gmail.com>")
                        .arg(Arg::new("flag")
                                    .short("f")
                                    .long("flag")
                                    .help("tests flags")
                                    .multiple(true))
                        .arg(Arg::new("option")
                                    .short("o")
                                    .long("option")
                                    .required(true)
                                    .help("tests options")
                                    .takes_value(true)
                                    .multiple(true))
                        .arg(Arg::new("positional")
                                    .index(1)
                                    .help("tests positionals"))
                        .args(vec![
                            Arg::new("flag2").short("F").mutually_excludes("flag").help("tests flags with exclusions").requires("option2"),
                            Arg::new("option2").long("long-option-2").mutually_excludes("option").help("tests long options with exclusions and requirements").requires_all(vec!["positional", "positional2"]),
                            Arg::new("positional2").index(2).help("tests positionals with exclusions and multiple"),
                            Arg::new("option3").takes_value(true).short("O").possible_values(vec!["fast", "slow"]).help("test options with specific value sets").requires("positional3"),
                            Arg::new("positional3").index(3).multiple(true).possible_values(vec!["vi", "emacs"]).help("tests positionals with specific value sets")
                        ])
                        .subcommand(SubCommand::new("subcmd")
                                                .about("tests subcommands")
                                                .version("0.1")
                                                .author("Kevin K. <kbknapp@gmail.com>")
                                                .arg(Arg::new("scflag")
                                                            .short("f")
                                                            .long("flag")
                                                            .help("tests flags")
                                                            .multiple(true))
                                                .arg(Arg::new("scoption")
                                                            .short("o")
                                                            .long("option")
                                                            .help("tests options")
                                                            .takes_value(true)
                                                            .multiple(true))
                                                .arg(Arg::new("scpositional")
                                                            .index(1)
                                                            .help("tests positionals")))
                        .get_matches();

    if matches.is_present("flag") {
        println!("flag present {} times", matches.occurrences_of("flag"));
    } else {
        println!("flag NOT present");
    }

    if matches.is_present("option") {
        if let Some(v) = matches.value_of("option") {
            println!("option present {} times with value: {}",matches.occurrences_of("option"), v);
        }
        if let Some(ref ov) = matches.values_of("option") {
            for o in ov {
                println!("An option: {}", o);
            }
        }
    } else {
        println!("option NOT present");
    }

    if let Some(p) = matches.value_of("positional") {
        println!("positional present with value: {}", p);
    } else {
        println!("positional NOT present");
    }

    if matches.is_present("flag2") {
        println!("flag2 present");
        println!("option2 present with value of: {}", matches.value_of("option2").unwrap());
        println!("positional2 present with value of: {}", matches.value_of("positional2").unwrap());
    } else {
        println!("flag2 NOT present");
        println!("option2 maybe present with value of: {}", matches.value_of("option2").unwrap_or("Nothing"));
        println!("positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing"));
    }

    match matches.value_of("option3").unwrap_or("") {
        "fast" => println!("option3 present quickly"),
        "slow" => println!("option3 present slowly"),
        _      => println!("option3 NOT present")
    }

    match matches.value_of("positional3").unwrap_or("") {
        "vi" => println!("positional3 present in vi mode"),
        "emacs" => println!("positional3 present in emacs mode"),
        _      => println!("positional3 NOT present")
    }

    if matches.is_present("option") {
        if let Some(v) = matches.value_of("option") {
            println!("option present {} times with value: {}",matches.occurrences_of("option"), v);
        }
        if let Some(ref ov) = matches.values_of("option") {
            for o in ov {
                println!("An option: {}", o);
            }
        }
    } else {
        println!("option NOT present");
    }

    if let Some(p) = matches.value_of("positional") {
        println!("positional present with value: {}", p);
    } else {
        println!("positional NOT present");
    }
    if matches.is_present("subcmd") {
        println!("subcmd present");
        if let Some(matches) = matches.subcommand_matches("subcmd") {
            if matches.is_present("scflag") {
                println!("scflag present {} times", matches.occurrences_of("scflag"));
            } else {
                println!("scflag NOT present");
            }

            if matches.is_present("scoption") {
                if let Some(v) = matches.value_of("scoption") {
                    println!("scoption present with value: {}", v);
                }
                if let Some(ref ov) = matches.values_of("scoption") {
                    for o in ov {
                        println!("An scoption: {}", o);
                    }
                }
            } else {
                println!("scoption NOT present");
            }

            if let Some(p) = matches.value_of("scpositional") {
                println!("scpositional present with value: {}", p);
            }
        }
    } else {
        println!("subcmd NOT present");
    }
}
<commit_msg>fix(tests): add missing .takes_value(true) to option2<commit_after>extern crate clap;

use clap::{App, Arg, SubCommand};

fn main() {
    // Test version from Cargo.toml
    let version = format!("{}.{}.{}{}",
                          env!("CARGO_PKG_VERSION_MAJOR"),
                          env!("CARGO_PKG_VERSION_MINOR"),
                          env!("CARGO_PKG_VERSION_PATCH"),
                          option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
    let matches = App::new("claptests")
                        .version(&version[..])
                        .about("tests clap library")
                        .author("Kevin K. <kbknapp@gmail.com>")
                        .arg(Arg::new("flag")
                                    .short("f")
                                    .long("flag")
                                    .help("tests flags")
                                    .multiple(true))
                        .arg(Arg::new("option")
                                    .short("o")
                                    .long("option")
                                    .required(true)
                                    .help("tests options")
                                    .takes_value(true)
                                    .multiple(true))
                        .arg(Arg::new("positional")
                                    .index(1)
                                    .help("tests positionals"))
                        .args(vec![
                            Arg::new("flag2").short("F").mutually_excludes("flag").help("tests flags with exclusions").requires("option2"),
                            Arg::new("option2").takes_value(true).long("long-option-2").mutually_excludes("option").help("tests long options with exclusions and requirements").requires_all(vec!["positional", "positional2"]),
                            Arg::new("positional2").index(2).help("tests positionals with exclusions and multiple"),
                            Arg::new("option3").takes_value(true).short("O").possible_values(vec!["fast", "slow"]).help("test options with specific value sets").requires("positional3"),
                            Arg::new("positional3").index(3).multiple(true).possible_values(vec!["vi", "emacs"]).help("tests positionals with specific value sets")
                        ])
                        .subcommand(SubCommand::new("subcmd")
                                                .about("tests subcommands")
                                                .version("0.1")
                                                .author("Kevin K. <kbknapp@gmail.com>")
                                                .arg(Arg::new("scflag")
                                                            .short("f")
                                                            .long("flag")
                                                            .help("tests flags")
                                                            .multiple(true))
                                                .arg(Arg::new("scoption")
                                                            .short("o")
                                                            .long("option")
                                                            .help("tests options")
                                                            .takes_value(true)
                                                            .multiple(true))
                                                .arg(Arg::new("scpositional")
                                                            .index(1)
                                                            .help("tests positionals")))
                        .get_matches();

    if matches.is_present("flag") {
        println!("flag present {} times", matches.occurrences_of("flag"));
    } else {
        println!("flag NOT present");
    }

    if matches.is_present("option") {
        if let Some(v) = matches.value_of("option") {
            println!("option present {} times with value: {}",matches.occurrences_of("option"), v);
        }
        if let Some(ref ov) = matches.values_of("option") {
            for o in ov {
                println!("An option: {}", o);
            }
        }
    } else {
        println!("option NOT present");
    }

    if let Some(p) = matches.value_of("positional") {
        println!("positional present with value: {}", p);
    } else {
        println!("positional NOT present");
    }

    if matches.is_present("flag2") {
        println!("flag2 present");
        println!("option2 present with value of: {}", matches.value_of("option2").unwrap());
        println!("positional2 present with value of: {}", matches.value_of("positional2").unwrap());
    } else {
        println!("flag2 NOT present");
        println!("option2 maybe present with value of: {}", matches.value_of("option2").unwrap_or("Nothing"));
        println!("positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing"));
    }

    match matches.value_of("option3").unwrap_or("") {
        "fast" => println!("option3 present quickly"),
        "slow" => println!("option3 present slowly"),
        _      => println!("option3 NOT present")
    }

    match matches.value_of("positional3").unwrap_or("") {
        "vi" => println!("positional3 present in vi mode"),
        "emacs" => println!("positional3 present in emacs mode"),
        _      => println!("positional3 NOT present")
    }

    if matches.is_present("option") {
        if let Some(v) = matches.value_of("option") {
            println!("option present {} times with value: {}",matches.occurrences_of("option"), v);
        }
        if let Some(ref ov) = matches.values_of("option") {
            for o in ov {
                println!("An option: {}", o);
            }
        }
    } else {
        println!("option NOT present");
    }

    if let Some(p) = matches.value_of("positional") {
        println!("positional present with value: {}", p);
    } else {
        println!("positional NOT present");
    }
    if matches.is_present("subcmd") {
        println!("subcmd present");
        if let Some(matches) = matches.subcommand_matches("subcmd") {
            if matches.is_present("scflag") {
                println!("scflag present {} times", matches.occurrences_of("scflag"));
            } else {
                println!("scflag NOT present");
            }

            if matches.is_present("scoption") {
                if let Some(v) = matches.value_of("scoption") {
                    println!("scoption present with value: {}", v);
                }
                if let Some(ref ov) = matches.values_of("scoption") {
                    for o in ov {
                        println!("An scoption: {}", o);
                    }
                }
            } else {
                println!("scoption NOT present");
            }

            if let Some(p) = matches.value_of("scpositional") {
                println!("scpositional present with value: {}", p);
            }
        }
    } else {
        println!("subcmd NOT present");
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::sync::Arc;

use VulkanObject;
use buffer::Buffer;
use formats::Format;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum VertexInputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. More precisely, a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<VertexAttribute>;
}

pub struct VertexAttribute {
    pub offset: usize,
    pub format: Format,
}

/// Trait for types that contain the layout of a collection of vertex buffers.
pub unsafe trait MultiVertex {
    fn attrib(name: &str) -> Option<(u32, VertexAttribute)>;

    /// Returns the number of buffers in this collection.
    fn num_buffers() -> u32;

    fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate);

    // TODO: hacky
    fn ids(&self) -> Vec<u64>;
}

unsafe impl<T, M> MultiVertex for Arc<Buffer<T, M>> where T: Vertex {
    #[inline]
    fn attrib(name: &str) -> Option<(u32, VertexAttribute)> {
        T::attrib(name).map(|attr| (0, attr))
    }

    #[inline]
    fn num_buffers() -> u32 {
        1
    }

    #[inline]
    fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate) {
        assert_eq!(buffer_id, 0);
        (mem::size_of::<T>() as u32, VertexInputRate::Vertex)
    }

    fn ids(&self) -> Vec<u64> {
        vec![self.internal_object()]
    }
}

unsafe impl<T, M> MultiVertex for Arc<Buffer<[T], M>> where T: Vertex {
    #[inline]
    fn attrib(name: &str) -> Option<(u32, VertexAttribute)> {
        T::attrib(name).map(|attr| (0, attr))
    }

    #[inline]
    fn num_buffers() -> u32 {
        1
    }

    #[inline]
    fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate) {
        assert_eq!(buffer_id, 0);
        (mem::size_of::<T>() as u32, VertexInputRate::Vertex)
    }

    fn ids(&self) -> Vec<u64> {
        vec![self.internal_object()]
    }
}

macro_rules! impl_mv {
    ($t1:ident, $t2:ty) => (
        unsafe impl<$t1, M> MultiVertex for Arc<Buffer<$t2, M>> where T: Vertex {
            #[inline]
            fn attrib(name: &str) -> Option<(u32, VertexAttribute)> {
                T::attrib(name).map(|attr| (0, attr))
            }

            #[inline]
            fn num_buffers() -> u32 {
                1
            }

            #[inline]
            fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate) {
                assert_eq!(buffer_id, 0);
                (mem::size_of::<T>() as u32, VertexInputRate::Vertex)
            }

            fn ids(&self) -> Vec<u64> {
                vec![self.internal_object()]
            }
        }
    );
}

impl_mv!(T, [T; 1]);
impl_mv!(T, [T; 2]);
impl_mv!(T, [T; 3]);
impl_mv!(T, [T; 4]);
impl_mv!(T, [T; 5]);
impl_mv!(T, [T; 6]);
impl_mv!(T, [T; 7]);
impl_mv!(T, [T; 8]);
impl_mv!(T, [T; 9]);
impl_mv!(T, [T; 10]);
impl_mv!(T, [T; 11]);
impl_mv!(T, [T; 12]);
impl_mv!(T, [T; 13]);
impl_mv!(T, [T; 14]);
impl_mv!(T, [T; 15]);
impl_mv!(T, [T; 16]);
impl_mv!(T, [T; 32]);
impl_mv!(T, [T; 64]);
impl_mv!(T, [T; 128]);
impl_mv!(T, [T; 256]);
impl_mv!(T, [T; 512]);
impl_mv!(T, [T; 1024]);
impl_mv!(T, [T; 2048]);
impl_mv!(T, [T; 4096]);

#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::VertexAttribute> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::VertexAttribute {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Attribute>(_: &T) -> $crate::formats::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

pub unsafe trait Attribute {
    fn format() -> Format;
}

unsafe impl Attribute for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Attribute for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Attribute for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Attribute for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}
<commit_msg>Implement vertex attribute trait for f32<commit_after>use std::mem;
use std::sync::Arc;

use VulkanObject;
use buffer::Buffer;
use formats::Format;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum VertexInputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. More precisely, a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<VertexAttribute>;
}

pub struct VertexAttribute {
    pub offset: usize,
    pub format: Format,
}

/// Trait for types that contain the layout of a collection of vertex buffers.
pub unsafe trait MultiVertex {
    fn attrib(name: &str) -> Option<(u32, VertexAttribute)>;

    /// Returns the number of buffers in this collection.
    fn num_buffers() -> u32;

    fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate);

    // TODO: hacky
    fn ids(&self) -> Vec<u64>;
}

unsafe impl<T, M> MultiVertex for Arc<Buffer<T, M>> where T: Vertex {
    #[inline]
    fn attrib(name: &str) -> Option<(u32, VertexAttribute)> {
        T::attrib(name).map(|attr| (0, attr))
    }

    #[inline]
    fn num_buffers() -> u32 {
        1
    }

    #[inline]
    fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate) {
        assert_eq!(buffer_id, 0);
        (mem::size_of::<T>() as u32, VertexInputRate::Vertex)
    }

    fn ids(&self) -> Vec<u64> {
        vec![self.internal_object()]
    }
}

unsafe impl<T, M> MultiVertex for Arc<Buffer<[T], M>> where T: Vertex {
    #[inline]
    fn attrib(name: &str) -> Option<(u32, VertexAttribute)> {
        T::attrib(name).map(|attr| (0, attr))
    }

    #[inline]
    fn num_buffers() -> u32 {
        1
    }

    #[inline]
    fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate) {
        assert_eq!(buffer_id, 0);
        (mem::size_of::<T>() as u32, VertexInputRate::Vertex)
    }

    fn ids(&self) -> Vec<u64> {
        vec![self.internal_object()]
    }
}

macro_rules! impl_mv {
    ($t1:ident, $t2:ty) => (
        unsafe impl<$t1, M> MultiVertex for Arc<Buffer<$t2, M>> where T: Vertex {
            #[inline]
            fn attrib(name: &str) -> Option<(u32, VertexAttribute)> {
                T::attrib(name).map(|attr| (0, attr))
            }

            #[inline]
            fn num_buffers() -> u32 {
                1
            }

            #[inline]
            fn buffer_info(buffer_id: u32) -> (u32, VertexInputRate) {
                assert_eq!(buffer_id, 0);
                (mem::size_of::<T>() as u32, VertexInputRate::Vertex)
            }

            fn ids(&self) -> Vec<u64> {
                vec![self.internal_object()]
            }
        }
    );
}

impl_mv!(T, [T; 1]);
impl_mv!(T, [T; 2]);
impl_mv!(T, [T; 3]);
impl_mv!(T, [T; 4]);
impl_mv!(T, [T; 5]);
impl_mv!(T, [T; 6]);
impl_mv!(T, [T; 7]);
impl_mv!(T, [T; 8]);
impl_mv!(T, [T; 9]);
impl_mv!(T, [T; 10]);
impl_mv!(T, [T; 11]);
impl_mv!(T, [T; 12]);
impl_mv!(T, [T; 13]);
impl_mv!(T, [T; 14]);
impl_mv!(T, [T; 15]);
impl_mv!(T, [T; 16]);
impl_mv!(T, [T; 32]);
impl_mv!(T, [T; 64]);
impl_mv!(T, [T; 128]);
impl_mv!(T, [T; 256]);
impl_mv!(T, [T; 512]);
impl_mv!(T, [T; 1024]);
impl_mv!(T, [T; 2048]);
impl_mv!(T, [T; 4096]);

#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::VertexAttribute> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::VertexAttribute {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Attribute>(_: &T) -> $crate::formats::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

pub unsafe trait Attribute {
    fn format() -> Format;
}

unsafe impl Attribute for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Attribute for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Attribute for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Attribute for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Attribute for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}
<|endoftext|>


<commit_before><commit_msg>all tests passing for anagram<commit_after><|endoftext|>


<commit_before>use std::env;
use std::io::Write;
use std::fs::File;

static TEMPLATE: &'static str = "\
extern crate @UTIL_CRATE@ as uu@UTIL_CRATE@;

use std::env;
use uu@UTIL_CRATE@::uumain;

fn main() {
    std::process::exit(uumain(env::args().collect()));
}
";

fn main() {
    let args : Vec<String> = env::args().collect();
    if args.len() != 3 {
        println!("usage: mkbuild <crate> <outfile>");
        std::process::exit(1);
    }

    let crat    = match &args[1][..] {
        "false" => "uufalse",
        "test" => "uutest",
        "true" => "uutrue",
        _ => &args[1][..],
    };
    let outfile = &args[2][..];

    let main = TEMPLATE.replace("@UTIL_CRATE@", crat);
    match File::create(outfile) {
        Ok(mut out) => match out.write_all(main.as_bytes()) {
            Err(e) => panic!("{}", e),
            _ => (),
        },
        Err(e) => panic!("{}", e),
    }
}
<commit_msg>Ensure any pending stdout writes are flushed.<commit_after>use std::env;
use std::io::Write;
use std::fs::File;

static TEMPLATE: &'static str = "\
extern crate @UTIL_CRATE@ as uu@UTIL_CRATE@;

use std::io::Write;
use uu@UTIL_CRATE@::uumain;

fn main() {
    let code = uumain(std::env::args().collect());

    // Since stdout is line-buffered by default, we need to ensure any pending
    // writes are flushed before exiting. Ideally, this should be enforced by
    // each utility.
    //
    // See: https://github.com/rust-lang/rust/issues/23818
    //
    std::io::stdout().flush().unwrap();

    std::process::exit(code);
}
";

fn main() {
    let args : Vec<String> = env::args().collect();
    if args.len() != 3 {
        println!("usage: mkbuild <crate> <outfile>");
        std::process::exit(1);
    }

    let crat    = match &args[1][..] {
        "false" => "uufalse",
        "test" => "uutest",
        "true" => "uutrue",
        _ => &args[1][..],
    };
    let outfile = &args[2][..];

    let main = TEMPLATE.replace("@UTIL_CRATE@", crat);
    match File::create(outfile) {
        Ok(mut out) => match out.write_all(main.as_bytes()) {
            Err(e) => panic!("{}", e),
            _ => (),
        },
        Err(e) => panic!("{}", e),
    }
}
<|endoftext|>


<commit_before><commit_msg>ljpeg: avoid useless peek<commit_after><|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS x86_64 bootstrap
//!
//! This crate contains code for the 32-bit protected mode boot routine for
//! x86_64 CPUs. When we boot up an x86_64 system using GRUB & multiboot, we
//! end up with the CPU running in 32-bit 'protected mode', rather than 64-bit
//! 'long mode'. Before we can jump into long mode, we have to perform a
//! handful of setup tasks in protected mode.
//!
//! This boot routine lives in a separate crate, with a 32-bit `target.json`.
//! When building SOS for x86_64, we have to compile this crate separately and
//! then link the resulting 32-bit object with the rest of the 64-bit kernel
//! object.
//!
//! This boot crate is only necessary for x86_64. For other architectures, all
//! boot code can live in the main kernel crate.
//!
//! For more information, refer to:
//! + the [intermezzOS book]
//! + the [OSDev Wiki] article on long mode
//! + Philipp Oppermann's [blog post]
//!
//! [intermezzOS book]: http://intermezzos.github.io/book/transitioning-to-long-mode.html
//! [OSDev Wiki]: http://wiki.osdev.org/Long_Mode#Long_Mode
//! [blog post]: http://os.phil-opp.com/entering-longmode.html

#![crate_name = "boot"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(static_recursion)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

extern crate rlibc;

const TABLE_LENGTH: usize = 512;
/// The size of a "huge" page
const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB
/// Page table entry flags for a page that is present and writable.
const ENTRY_FLAGS_PW: u64 = 0b11;
/// Page table entry flags for a page that is huge, present, and writable.
const ENTRY_FLAGS_HUGE: u64 = 0b10000000 & ENTRY_FLAGS_PW;

/// A page table is an array of page table entries.
type Table = [TableEntry; TABLE_LENGTH];

trait PageTable: Sized {
    /// Install this page table as the top-level page table.
    #[inline(always)]
    unsafe fn set_top_level(&'static self) {
        asm!("mov cr3, $0" :: "r"(self) :: "intel");
    }
}

impl PageTable for Table { }

/// A page table entry is a 64-bit unsigned integer.
///
/// We represent this as a [newtype] rather than a type alias, because we want
/// to implement specific functionality on it.
///
/// [newtype]: https://aturon.github.io/features/types/newtype.html
#[repr(C)]
struct TableEntry(u64);

impl TableEntry {
    /// Set this table entry to map to a lower-level page table.
    // TODO: use a marker type to ensure this always maps to a _lower-level_
    //       table?
    #[inline(always)]
    unsafe fn map_to_table(&mut self, to: &'static Table) {
        *self = TableEntry(to as *const _ as u64 | ENTRY_FLAGS_PW);
    }

    /// Set this table entry to map to a huge page with the given number.
    #[inline(always)]
    unsafe fn map_to_page(&mut self, number: usize) {

        // the start address is the page number times the page's size
        let addr = number as u64 * HUGE_PAGE_SIZE;
        *self = TableEntry(addr | ENTRY_FLAGS_HUGE);
    }

}

use core::convert;

macro_rules! set_flags {
    (%$register:ident $( |= $body:expr);+ ) => {
        let mut $register: usize;
        asm!( concat!("mov $0, ", stringify!($register))
            : "=r"($register)
            ::: "intel");
        $($register |= $body;)+
        asm!( concat!("mov ", stringify!($register), ", $0")
            :: "r"($register)
            :: "intel");
    }
}

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the GDT
                        pub limit: u16
                      , /// pointer to the GDT
                        pub base: &'static Gdt
                      }

impl GdtPointer {
    #[cold] #[inline(always)]
    unsafe fn load (&self) {
        asm!("lgdt ($0)" :: "r"(self) : "memory");
    }
}

impl convert::From<&'static Gdt> for GdtPointer {
    #[cold] #[inline(always)]
    fn from(gdt: &'static Gdt) -> Self {
        use core::mem::size_of_val;
        GdtPointer { limit: size_of_val(gdt) as u16 - 1
                   , base: gdt }
    }
}

#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
          };

#[inline(always)]
fn boot_write(s: &[u8]) {
    unsafe {
        use core::ptr::write_volatile;
        let vga_buf = 0xb8000 as *mut u16;
    	for (n, c) in s.iter().enumerate() {
    		write_volatile(vga_buf.offset(n as isize), 0x0200 + *c as u16);
    	}

    }

}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;
}

#[cold]
#[inline(always)]
#[naked]
unsafe fn create_page_tables() {
    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511].map_to_table(&pml4_table);
    // map first PML4 entry to PDP table
    pml4_table[0].map_to_table(&pdp_table);
    // map first PDPT entry to PD table
    pdp_table[0].map_to_table(&pd_table);

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (page_number, entry) in pd_table.iter_mut().enumerate() {
        entry.map_to_page(page_number);
    }

    boot_write(b"3.2");
}

#[cold]
#[inline(always)]
unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    &pml4_table.set_top_level();
    boot_write(b"3.3");

    // // enable PAE flag in cr4
    set_flags!(%cr4 |= 1 << 5 );
    boot_write(b"3.4");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::: "intel");
    boot_write(b"3.5");

    // enable paging in cr0
    set_flags!(%cr0 |= 1 << 31;
                    |= 1 << 16 );
    boot_write(b"3.6")
}

/// Test whether or not this system supports Multiboot 2
#[cold]
#[inline(always)]
unsafe fn is_multiboot_supported() -> bool {
    const MULTIBOOT_MAGIC: usize = 0x36d76289;
    let eax: usize;
    asm!("mov eax, $0" : "=r"(eax) ::: "intel");
    eax == MULTIBOOT_MAGIC
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    asm!("mov edi, ebx" :::: "intel");
    boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    if !is_multiboot_supported() {
        loop { boot_write(b"ERROR: multiboot not supported!"); }
    }
    boot_write(b"2");

    // 3. if everything is okay, create the page tables and start long mode
    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    GdtPointer::from(&GDT).load();
    boot_write(b"4");

    // 6. jump to the 64-bit boot subroutine.
    asm!("ljmpl $$8, $$long_mode_init");

}
<commit_msg>[boot] fix weird boot loop introduced in commit 777984b<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS x86_64 bootstrap
//!
//! This crate contains code for the 32-bit protected mode boot routine for
//! x86_64 CPUs. When we boot up an x86_64 system using GRUB & multiboot, we
//! end up with the CPU running in 32-bit 'protected mode', rather than 64-bit
//! 'long mode'. Before we can jump into long mode, we have to perform a
//! handful of setup tasks in protected mode.
//!
//! This boot routine lives in a separate crate, with a 32-bit `target.json`.
//! When building SOS for x86_64, we have to compile this crate separately and
//! then link the resulting 32-bit object with the rest of the 64-bit kernel
//! object.
//!
//! This boot crate is only necessary for x86_64. For other architectures, all
//! boot code can live in the main kernel crate.
//!
//! For more information, refer to:
//! + the [intermezzOS book]
//! + the [OSDev Wiki] article on long mode
//! + Philipp Oppermann's [blog post]
//!
//! [intermezzOS book]: http://intermezzos.github.io/book/transitioning-to-long-mode.html
//! [OSDev Wiki]: http://wiki.osdev.org/Long_Mode#Long_Mode
//! [blog post]: http://os.phil-opp.com/entering-longmode.html

#![crate_name = "boot"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(static_recursion)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

extern crate rlibc;

const TABLE_LENGTH: usize = 512;
/// The size of a "huge" page
const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB
/// Page table entry flags for a page that is present and writable.
const ENTRY_FLAGS_PW: u64 = 0b11;

/// A page table is an array of page table entries.
type Table = [TableEntry; TABLE_LENGTH];

trait PageTable: Sized {
    /// Install this page table as the top-level page table.
    #[inline(always)]
    unsafe fn set_top_level(&'static self) {
        asm!("mov cr3, $0" :: "r"(self) :: "intel");
    }
}

impl PageTable for Table { }

/// A page table entry is a 64-bit unsigned integer.
///
/// We represent this as a [newtype] rather than a type alias, because we want
/// to implement specific functionality on it.
///
/// [newtype]: https://aturon.github.io/features/types/newtype.html
#[repr(C)]
struct TableEntry(u64);

impl TableEntry {
    /// Set this table entry to map to a lower-level page table.
    // TODO: use a marker type to ensure this always maps to a _lower-level_
    //       table?
    #[inline(always)]
    unsafe fn map_to_table(&mut self, to: &'static Table) {
        *self = TableEntry(to as *const _ as u64 | ENTRY_FLAGS_PW);
    }

    /// Set this table entry to map to a huge page with the given number.
    #[inline(always)]
    unsafe fn map_to_page(&mut self, number: usize) {
        // Page table entry flags for a page that is huge, present, and writable.
        const ENTRY_FLAGS_HUGE: u64 = 0b10000011;
        // the start address is the page number times the page's size
        let addr = number as u64 * HUGE_PAGE_SIZE;
        *self = TableEntry(addr | ENTRY_FLAGS_HUGE);
    }

}

use core::convert;

macro_rules! set_flags {
    (%$register:ident $( |= $body:expr);+ ) => {
        let mut $register: usize;
        asm!( concat!("mov $0, ", stringify!($register))
            : "=r"($register)
            ::: "intel");
        $($register |= $body;)+
        asm!( concat!("mov ", stringify!($register), ", $0")
            :: "r"($register)
            :: "intel");
    }
}

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the GDT
                        pub limit: u16
                      , /// pointer to the GDT
                        pub base: &'static Gdt
                      }

impl GdtPointer {
    #[cold] #[inline(always)]
    unsafe fn load (&self) {
        asm!("lgdt ($0)" :: "r"(self) : "memory");
    }
}

impl convert::From<&'static Gdt> for GdtPointer {
    #[cold] #[inline(always)]
    fn from(gdt: &'static Gdt) -> Self {
        use core::mem::size_of_val;
        GdtPointer { limit: size_of_val(gdt) as u16 - 1
                   , base: gdt }
    }
}

#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
          };

#[inline(always)]
fn boot_write(s: &[u8]) {
    unsafe {
        use core::ptr::write_volatile;
        let vga_buf = 0xb8000 as *mut u16;
    	for (n, c) in s.iter().enumerate() {
    		write_volatile(vga_buf.offset(n as isize), 0x0200 + *c as u16);
    	}

    }

}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;
}

#[cold]
#[inline(always)]
#[naked]
unsafe fn create_page_tables() {
    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511].map_to_table(&pml4_table);
    // map first PML4 entry to PDP table
    pml4_table[0].map_to_table(&pdp_table);
    // map first PDPT entry to PD table
    pdp_table[0].map_to_table(&pd_table);

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (page_number, entry) in pd_table.iter_mut().enumerate() {
        entry.map_to_page(page_number);
    }

    boot_write(b"3.2");
}

#[cold]
#[inline(always)]
unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    &pml4_table.set_top_level();
    boot_write(b"3.3");

    // // enable PAE flag in cr4
    set_flags!(%cr4 |= 1 << 5 );
    boot_write(b"3.4");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::: "intel");
    boot_write(b"3.5");

    // enable paging in cr0
    set_flags!(%cr0 |= 1 << 31;
                    |= 1 << 16 );
    boot_write(b"3.6")
}

/// Test whether or not this system supports Multiboot 2
#[cold]
#[inline(always)]
unsafe fn is_multiboot_supported() -> bool {
    const MULTIBOOT_MAGIC: usize = 0x36d76289;
    let eax: usize;
    asm!("mov eax, $0" : "=r"(eax) ::: "intel");
    eax == MULTIBOOT_MAGIC
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    asm!("mov edi, ebx" :::: "intel");
    boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    if !is_multiboot_supported() {
        loop { boot_write(b"ERROR: multiboot not supported!"); }
    }
    boot_write(b"2");

    // 3. if everything is okay, create the page tables and start long mode
    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    GdtPointer::from(&GDT).load();
    boot_write(b"4");

    // 6. jump to the 64-bit boot subroutine.
    asm!("ljmpl $$8, $$long_mode_init");

}
<|endoftext|>


<commit_before>extern crate tui;
extern crate termion;
extern crate nalgebra;
extern crate steering;
extern crate alga;

use std::io;
use std::thread;
use std::time;
use std::sync::mpsc;

use termion::event;
use termion::input::TermRead;

use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, SelectableList, List};
use tui::widgets::canvas::{Canvas, Map, MapResolution, Line};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

use nalgebra::Vector3;
use alga::general::AbstractModule;
use steering::Steerable;
use steering::SteeringAcceleration;
use steering::Seek;
use steering::SteeringAccelerationCalculator;
use steering::SteeringBehavior;

struct App<'a> {
    items: Vec<&'a str>,
    selected: usize,
    events: Vec<(&'a str, &'a str)>,
    info_style: Style,
    warning_style: Style,
    error_style: Style,
    critical_style: Style,
    v : Vehicle<'a>,
    t : Target,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            items: vec!["Seek", "Flee", "Pursue"],
            selected: 0,
            events: vec![("Event1", "INFO"),
                         ("Event2", "INFO"),
                         ("Event3", "CRITICAL"),
                         ("Event4", "ERROR"),
                         ("Event5", "INFO"),
                         ("Event6", "INFO"),
                         ("Event7", "WARNING"),
                         ("Event8", "INFO"),
                         ("Event9", "INFO"),
                         ("Event10", "INFO"),
                         ("Event11", "CRITICAL"),
                         ("Event12", "INFO"),
                         ("Event13", "INFO"),
                         ("Event14", "INFO"),
                         ("Event15", "INFO"),
                         ("Event16", "INFO"),
                         ("Event17", "ERROR"),
                         ("Event18", "ERROR"),
                         ("Event19", "INFO"),
                         ("Event20", "INFO"),
                         ("Event21", "WARNING"),
                         ("Event22", "INFO"),
                         ("Event23", "INFO"),
                         ("Event24", "WARNING"),
                         ("Event25", "INFO"),
                         ("Event26", "INFO")],
            info_style: Style::default().fg(Color::White),
            warning_style: Style::default().fg(Color::Yellow),
            error_style: Style::default().fg(Color::Magenta),
            critical_style: Style::default().fg(Color::Red),
            v: Vehicle::new(),
            t : Target::new(),
        }
    }

    fn advance(&mut self) {
        let event = self.events.pop().unwrap();
        self.events.insert(0, event);
    }
}

enum Event {
    Input(event::Key),
    Tick,
}

struct Target{
   pub  position : Vector3<f32>
}

impl Target{
    fn new()->Self{
        Target{
            position : Vector3::new(0.0,0.0,0.0),
        }
    }
}

struct Vehicle<'a>{
    linear_velocity : Vector3<f32>,
    position : Vector3<f32>,
    angular_velocity : f32,
    bounding_radius : f32,
    behavior : &'a (SteeringAccelerationCalculator<f32> + 'a),
}

impl<'a> Steerable<f32> for Vehicle<'a>{
    fn get_linear_velocity(&self) -> &Vector3<f32>{
        &self.linear_velocity
    }

    fn get_angular_velocity(&self) -> f32 {
        self.angular_velocity
    }

    fn get_bounding_radius(&self) -> f32 {
        self.bounding_radius
    }

    fn get_position(&self) -> &Vector3<f32> {
        &self.position
    }
}

impl<'a> Vehicle<'a>{
    fn new() -> Self {
        Vehicle{
            linear_velocity : Vector3::new(1.0, 0.0, 0.0),
            position  : Vector3::new(-10.0, 0.0, 0.0),
            angular_velocity : 0.0,
            bounding_radius : 2.0,
             behavior :  &Seek{
                behavior : SteeringBehavior{
                    owner : &self,
                    enabled : true,
                    limiter : None,
                },
                target : Vector3::new(0.0, 0.0, 0.0),
            },
        }
    }
    fn advance(&mut self, milis : f32){
        self.position = self.position + self.linear_velocity.multiply_by(milis/1000.0);
    }
}

fn main() {
    // Terminal initialization
    let backend = TermionBackend::new().unwrap();
    let mut terminal = Terminal::new(backend).unwrap();
    let (tx, rx) = mpsc::channel();
    let input_tx = tx.clone();
    let clock_tx = tx.clone();

    // Input
    thread::spawn(move || {
        let stdin = io::stdin();
        for c in stdin.keys() {
            let evt = c.unwrap();
            input_tx.send(Event::Input(evt)).unwrap();
            if evt == event::Key::Char('q') {
                break;
            }
        }
    });

    // Tick
    thread::spawn(move || {
        loop {
            clock_tx.send(Event::Tick).unwrap();
            thread::sleep(time::Duration::from_millis(500));
        }
    });

    // App
    let mut app = App::new();

    // First draw call
    terminal.clear().unwrap();
    terminal.hide_cursor().unwrap();
    draw(&mut terminal, &app);

    loop {
        let evt = rx.recv().unwrap();
        match evt {
            Event::Input(input) => {
                match input {
                    event::Key::Char('q') => {
                        break;
                    }
                    event::Key::Down => {
                        app.selected += 1;
                        if app.selected > app.items.len() - 1 {
                            app.selected = 0;
                        }
                    }
                    event::Key::Up => {
                        if app.selected > 0 {
                            app.selected -= 1;
                        } else {
                            app.selected = app.items.len() - 1;
                        }
                    }
                    _ => {}
                }
            }
            Event::Tick => {
                app.advance();
            }
        }
        draw(&mut terminal, &app);
    }

    terminal.show_cursor().unwrap();
}

fn draw(t: &mut Terminal<TermionBackend>, app: &App) {

    let size = t.size().unwrap();

    Group::default()
        .direction(Direction::Vertical)
        .sizes(&[Size::Percent(90), Size::Percent(10)])
        .render(t, &size, |t, chunks| {
            Group::default()
                .direction(Direction::Horizontal)
                .sizes(&[Size::Percent(15), Size::Percent(85)])
                .render(t, &chunks[0], |t, chunks|{
                    SelectableList::default()
                        .block(Block::default()
                               .borders(border::ALL)
                               .title("Steering Behaviors")
                              )
                        .items(&app.items)
                        .select(app.selected)
                        .highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::Bold))
                        .highlight_symbol(">")
                        .render(t, &chunks[0]);

                    Canvas::default()
                        .block(Block::default()
                               .borders(border::ALL)
                               .title("Steering Actors")
                              )
                        .paint(|ctx|{
                            ctx.draw(&Map{
                                color : Color::Red,
                                resolution : MapResolution::High,
                            });
                        })
                        .x_bounds([-180.0, 180.0])
                        .y_bounds([-90.0,  90.0])
                        .render(t,&chunks[1]);
                });

            Block::default()
                .borders(border::ALL)
                .title("Instructions")
                .title_style(
                    Style::default()
                    .fg(Color::White)
                    .bg(Color::Red)
                    .modifier(Modifier::Bold)
                            )
                .render(t, &chunks[1]);
        });

    t.draw().unwrap();
}
<commit_msg>owner struct field refactored as function parameter and code refrmatted<commit_after>extern crate tui;
extern crate termion;
extern crate nalgebra;
extern crate steering;
extern crate alga;

use std::io;
use std::thread;
use std::time;
use std::sync::mpsc;

use termion::event;
use termion::input::TermRead;

use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, SelectableList, List};
use tui::widgets::canvas::{Canvas, Map, MapResolution, Line};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

use nalgebra::Vector3;
use alga::general::AbstractModule;
use steering::Steerable;
use steering::SteeringAcceleration;
use steering::Seek;
use steering::SteeringAccelerationCalculator;
use steering::SteeringBehavior;

struct App<'a> {
    items: Vec<&'a str>,
    selected: usize,
    events: Vec<(&'a str, &'a str)>,
    info_style: Style,
    warning_style: Style,
    error_style: Style,
    critical_style: Style,
    v: Vehicle,
    t: Target,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            items: vec!["Seek", "Flee", "Pursue"],
            selected: 0,
            events: vec![("Event1", "INFO"),
                         ("Event2", "INFO"),
                         ("Event3", "CRITICAL"),
                         ("Event4", "ERROR"),
                         ("Event5", "INFO"),
                         ("Event6", "INFO"),
                         ("Event7", "WARNING"),
                         ("Event8", "INFO"),
                         ("Event9", "INFO"),
                         ("Event10", "INFO"),
                         ("Event11", "CRITICAL"),
                         ("Event12", "INFO"),
                         ("Event13", "INFO"),
                         ("Event14", "INFO"),
                         ("Event15", "INFO"),
                         ("Event16", "INFO"),
                         ("Event17", "ERROR"),
                         ("Event18", "ERROR"),
                         ("Event19", "INFO"),
                         ("Event20", "INFO"),
                         ("Event21", "WARNING"),
                         ("Event22", "INFO"),
                         ("Event23", "INFO"),
                         ("Event24", "WARNING"),
                         ("Event25", "INFO"),
                         ("Event26", "INFO")],
            info_style: Style::default().fg(Color::White),
            warning_style: Style::default().fg(Color::Yellow),
            error_style: Style::default().fg(Color::Magenta),
            critical_style: Style::default().fg(Color::Red),
            v: Vehicle::new(),
            t: Target::new(),
        }
    }

    fn advance(&mut self) {
        let event = self.events.pop().unwrap();
        self.events.insert(0, event);
    }
}

enum Event {
    Input(event::Key),
    Tick,
}

struct Target {
    pub position: Vector3<f32>,
}

impl Target {
    fn new() -> Self {
        Target { position: Vector3::new(0.0, 0.0, 0.0) }
    }
}

struct Vehicle {
    linear_velocity: Vector3<f32>,
    position: Vector3<f32>,
    angular_velocity: f32,
    bounding_radius: f32,
}

impl Steerable<f32> for Vehicle {
    fn get_linear_velocity(&self) -> &Vector3<f32> {
        &self.linear_velocity
    }

    fn get_angular_velocity(&self) -> f32 {
        self.angular_velocity
    }

    fn get_bounding_radius(&self) -> f32 {
        self.bounding_radius
    }

    fn get_position(&self) -> &Vector3<f32> {
        &self.position
    }
}

impl Vehicle {
    fn new() -> Self {
        Vehicle {
            linear_velocity: Vector3::new(1.0, 0.0, 0.0),
            position: Vector3::new(-10.0, 0.0, 0.0),
            angular_velocity: 0.0,
            bounding_radius: 2.0,
        }
    }

    fn advance(&mut self, milis: f32) {
        self.position = self.position + self.linear_velocity.multiply_by(milis / 1000.0);
    }
}

fn main() {
    // Terminal initialization
    let backend = TermionBackend::new().unwrap();
    let mut terminal = Terminal::new(backend).unwrap();
    let (tx, rx) = mpsc::channel();
    let input_tx = tx.clone();
    let clock_tx = tx.clone();

    // Input
    thread::spawn(move || {
        let stdin = io::stdin();
        for c in stdin.keys() {
            let evt = c.unwrap();
            input_tx.send(Event::Input(evt)).unwrap();
            if evt == event::Key::Char('q') {
                break;
            }
        }
    });

    // Tick
    thread::spawn(move || {
        loop {
            clock_tx.send(Event::Tick).unwrap();
            thread::sleep(time::Duration::from_millis(500));
        }
    });

    // App
    let mut app = App::new();
    let mut behavior = Seek {
        behavior: SteeringBehavior {
            enabled: true,
            limiter: None,
        },
        target: app.t.position,
    };
    // First draw call
    terminal.clear().unwrap();
    terminal.hide_cursor().unwrap();
    draw(&mut terminal, &app);

    loop {
        let evt = rx.recv().unwrap();
        match evt {
            Event::Input(input) => {
                match input {
                    event::Key::Char('q') => {
                        break;
                    }
                    event::Key::Down => {
                        app.selected += 1;
                        if app.selected > app.items.len() - 1 {
                            app.selected = 0;
                        }
                    }
                    event::Key::Up => {
                        if app.selected > 0 {
                            app.selected -= 1;
                        } else {
                            app.selected = app.items.len() - 1;
                        }
                    }
                    _ => {}
                }
            }
            Event::Tick => {
                app.advance();
            }
        }
        draw(&mut terminal, &app);
    }

    terminal.show_cursor().unwrap();
}

fn draw(t: &mut Terminal<TermionBackend>, app: &App) {

    let size = t.size().unwrap();

    Group::default()
        .direction(Direction::Vertical)
        .sizes(&[Size::Percent(90), Size::Percent(10)])
        .render(t, &size, |t, chunks| {
            Group::default()
                .direction(Direction::Horizontal)
                .sizes(&[Size::Percent(15), Size::Percent(85)])
                .render(t, &chunks[0], |t, chunks| {
                    SelectableList::default()
                        .block(Block::default()
                                   .borders(border::ALL)
                                   .title("Steering Behaviors"))
                        .items(&app.items)
                        .select(app.selected)
                        .highlight_style(Style::default()
                                             .fg(Color::Yellow)
                                             .modifier(Modifier::Bold))
                        .highlight_symbol(">")
                        .render(t, &chunks[0]);

                    Canvas::default()
                        .block(Block::default()
                                   .borders(border::ALL)
                                   .title("Steering Actors"))
                        .paint(|ctx| {
                            ctx.draw(&Map {
                                color: Color::Red,
                                resolution: MapResolution::High,
                            });
                        })
                        .x_bounds([-180.0, 180.0])
                        .y_bounds([-90.0, 90.0])
                        .render(t, &chunks[1]);
                });

            Block::default()
                .borders(border::ALL)
                .title("Instructions")
                .title_style(Style::default()
                                 .fg(Color::White)
                                 .bg(Color::Red)
                                 .modifier(Modifier::Bold))
                .render(t, &chunks[1]);
        });

    t.draw().unwrap();
}
<|endoftext|>


<commit_before>// A version of pstree targetting linux written in rust!
//
// This is based on the following exercise from the excellent
// book "The Linux Programming Interface" by Michael Kerridsk.
//
//----------------------------------------------------------------------
//
// Write a program that draws a tree showing the hierarchical
// parent-child relationships of all processes on the system, going all
// the way back to init.  For each process, the program should display
// the process ID and the command being executed.  The output of the
// program should be similar to that produced by pstree(1), although it
// does need not to be as sophisticated.  The parent of each process on
// the system can be found by inspecing the PPid: line of all of the
// /proc/PID/status files on the system.  Be careful to handle the
// possibilty that a process's parent (and thus its /proc/PID directory)
// disappears during the scan of all /proc/PID directories.

// Implementation Notes
// --------------------
// The linux /proc filesystem is a virtual filesystem that provides information
// about processes running on a linux system among other things.  The /proc
// filesystem contains a directory, /proc/<pid>, for each running process in
// the system.
//
// Each process directory has a status file with contents including a bunch
// of different items, notably the process name and its parent process id (ppid).
// And with that information, we can build the process tree.

#![feature(path_ext)]

use std::path::Path;
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;

#[derive(Clone,Debug)]
struct ProcessRecord {
    name: String,
    pid: i32,
    ppid: i32,
}

#[derive(Clone,Debug)]
struct ProcessTreeNode {
    record: ProcessRecord,  // the node owns the associated record
    children: Vec<ProcessTreeNode>, // nodes own their children
}

#[derive(Clone,Debug)]
struct ProcessTree {
    root: ProcessTreeNode, // tree owns ref to root node
}

impl ProcessTreeNode {
    // constructor
    fn new(record : &ProcessRecord) -> ProcessTreeNode {
        ProcessTreeNode { record: (*record).clone(), children: Vec::new() }
    }
}

// Given a status file path, return a hashmap with the following form:
// pid -> ProcessRecord
fn get_process_record(status_path: &Path) -> Option<ProcessRecord> {
    let mut pid : Option<i32> = None;
    let mut ppid : Option<i32> = None;
    let mut name : Option<String> = None;

    let mut reader = std::io::BufReader::new(File::open(status_path).unwrap());
    loop {
        let mut linebuf = String::new();
        match reader.read_line(&mut linebuf) {
            Ok(_) => {
                if linebuf.is_empty() {
                    break;
                }
                let parts : Vec<&str> = linebuf[..].splitn(2, ':').collect();
                if parts.len() == 2 {
                    let key = parts[0].trim();
                    let value = parts[1].trim();
                    match key {
                        "Name" => name = Some(value.to_string()),
                        "Pid" => pid = value.parse().ok(),
                        "PPid" => ppid = value.parse().ok(),
                        _ => (),
                    }
                }
            },
            Err(_) => break,
        }
    }
    return if pid.is_some() && ppid.is_some() && name.is_some() {
        Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() })
    } else {
        None
    }
}

// build a simple struct (ProcessRecord) for each process
fn get_process_records() -> Vec<ProcessRecord> {
    let proc_directory = Path::new("/proc");

    // find potential process directories under /proc
    let proc_directory_contents = fs::read_dir(&proc_directory).unwrap();
    proc_directory_contents.filter_map(|entry| {
        let entry_path = entry.unwrap().path();
        if entry_path.is_dir() {
            let status_path = entry_path.join("status");
            if status_path.exists() {
                return get_process_record(&status_path)
            }
        }
        None
    }).collect()
}

fn populate_node_helper(node: &mut ProcessTreeNode, pid_map: &HashMap<i32, &ProcessRecord>, ppid_map: &HashMap<i32, Vec<i32>>) {
    let pid = node.record.pid; // avoid binding node as immutable in closure
    let child_nodes = &mut node.children;
    match ppid_map.get(&pid) {
        Some(children) => {
            child_nodes.extend(children.iter().map(|child_pid| {
                let record = pid_map[child_pid];
                let mut child = ProcessTreeNode::new(record);
                populate_node_helper(&mut child, pid_map, ppid_map);
                child
            }));
        },
        None => {},
    }
}

fn populate_node(node : &mut ProcessTreeNode, records: &Vec<ProcessRecord>) {
    // O(n): build a mapping of pids to vectors of children.  That is, each
    // key is a pid and its value is a vector of the whose parent pid is the key
    let mut ppid_map : HashMap<i32, Vec<i32>> = HashMap::new();
    let mut pid_map : HashMap<i32, &ProcessRecord> = HashMap::new();
    for record in records.iter() {
        // entry returns either a vacant or occupied entry.  If vacant,
        // we insert a new vector with this records pid.  If occupied,
        // we push this record's pid onto the vec
        pid_map.insert(record.pid, record);
        match ppid_map.entry(record.ppid) {
            Vacant(entry) => { entry.insert(vec![record.pid]); },
            Occupied(mut entry) => { entry.get_mut().push(record.pid); },
        };
    }

    // With the data structures built, it is off to the races
    populate_node_helper(node, &pid_map, &ppid_map);
}

fn build_process_tree() -> ProcessTree {
    let records = get_process_records();
    let mut tree = ProcessTree {
        root : ProcessTreeNode::new(
            &ProcessRecord {
                name: "/".to_string(),
                pid: 0,
                ppid: -1
            })
    };

    // recursively populate all nodes in the tree starting from root (pid 0)
    {
        let root = &mut tree.root;
        populate_node(root, &records);
    }
    tree
}

fn print_node(node : &ProcessTreeNode, indent_level : i32) {
    // print indentation
    for _ in (0..indent_level) {
        print!("  ");
    }
    println!("- {} #{}", node.record.name, node.record.pid);
    for child in node.children.iter() {
        print_node(child, indent_level + 1);  // recurse
    }
}

fn main() {
    let ptree = build_process_tree();
    print_node(&(ptree.root), 0)
}
<commit_msg>rustup: use only stable features of the language<commit_after>// A version of pstree targetting linux written in rust!
//
// This is based on the following exercise from the excellent
// book "The Linux Programming Interface" by Michael Kerridsk.
//
//----------------------------------------------------------------------
//
// Write a program that draws a tree showing the hierarchical
// parent-child relationships of all processes on the system, going all
// the way back to init.  For each process, the program should display
// the process ID and the command being executed.  The output of the
// program should be similar to that produced by pstree(1), although it
// does need not to be as sophisticated.  The parent of each process on
// the system can be found by inspecing the PPid: line of all of the
// /proc/PID/status files on the system.  Be careful to handle the
// possibilty that a process's parent (and thus its /proc/PID directory)
// disappears during the scan of all /proc/PID directories.

// Implementation Notes
// --------------------
// The linux /proc filesystem is a virtual filesystem that provides information
// about processes running on a linux system among other things.  The /proc
// filesystem contains a directory, /proc/<pid>, for each running process in
// the system.
//
// Each process directory has a status file with contents including a bunch
// of different items, notably the process name and its parent process id (ppid).
// And with that information, we can build the process tree.

use std::path::Path;
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;

#[derive(Clone,Debug)]
struct ProcessRecord {
    name: String,
    pid: i32,
    ppid: i32,
}

#[derive(Clone,Debug)]
struct ProcessTreeNode {
    record: ProcessRecord,  // the node owns the associated record
    children: Vec<ProcessTreeNode>, // nodes own their children
}

#[derive(Clone,Debug)]
struct ProcessTree {
    root: ProcessTreeNode, // tree owns ref to root node
}

impl ProcessTreeNode {
    // constructor
    fn new(record : &ProcessRecord) -> ProcessTreeNode {
        ProcessTreeNode { record: (*record).clone(), children: Vec::new() }
    }
}

// Given a status file path, return a hashmap with the following form:
// pid -> ProcessRecord
fn get_process_record(status_path: &Path) -> Option<ProcessRecord> {
    let mut pid : Option<i32> = None;
    let mut ppid : Option<i32> = None;
    let mut name : Option<String> = None;

    let mut reader = std::io::BufReader::new(File::open(status_path).unwrap());
    loop {
        let mut linebuf = String::new();
        match reader.read_line(&mut linebuf) {
            Ok(_) => {
                if linebuf.is_empty() {
                    break;
                }
                let parts : Vec<&str> = linebuf[..].splitn(2, ':').collect();
                if parts.len() == 2 {
                    let key = parts[0].trim();
                    let value = parts[1].trim();
                    match key {
                        "Name" => name = Some(value.to_string()),
                        "Pid" => pid = value.parse().ok(),
                        "PPid" => ppid = value.parse().ok(),
                        _ => (),
                    }
                }
            },
            Err(_) => break,
        }
    }
    return if pid.is_some() && ppid.is_some() && name.is_some() {
        Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() })
    } else {
        None
    }
}

// build a simple struct (ProcessRecord) for each process
fn get_process_records() -> Vec<ProcessRecord> {
    let proc_directory = Path::new("/proc");

    // find potential process directories under /proc
    let proc_directory_contents = fs::read_dir(&proc_directory).unwrap();
    proc_directory_contents.filter_map(|entry| {
        let entry_path = entry.unwrap().path();
        if fs::metadata(entry_path.as_path()).unwrap().is_dir() {
            let status_path = entry_path.join("status");
            if fs::metadata(status_path.as_path()).unwrap().is_file() {
                return get_process_record(status_path.as_path())
            }
        }
        None
    }).collect()
}

fn populate_node_helper(node: &mut ProcessTreeNode, pid_map: &HashMap<i32, &ProcessRecord>, ppid_map: &HashMap<i32, Vec<i32>>) {
    let pid = node.record.pid; // avoid binding node as immutable in closure
    let child_nodes = &mut node.children;
    match ppid_map.get(&pid) {
        Some(children) => {
            child_nodes.extend(children.iter().map(|child_pid| {
                let record = pid_map[child_pid];
                let mut child = ProcessTreeNode::new(record);
                populate_node_helper(&mut child, pid_map, ppid_map);
                child
            }));
        },
        None => {},
    }
}

fn populate_node(node : &mut ProcessTreeNode, records: &Vec<ProcessRecord>) {
    // O(n): build a mapping of pids to vectors of children.  That is, each
    // key is a pid and its value is a vector of the whose parent pid is the key
    let mut ppid_map : HashMap<i32, Vec<i32>> = HashMap::new();
    let mut pid_map : HashMap<i32, &ProcessRecord> = HashMap::new();
    for record in records.iter() {
        // entry returns either a vacant or occupied entry.  If vacant,
        // we insert a new vector with this records pid.  If occupied,
        // we push this record's pid onto the vec
        pid_map.insert(record.pid, record);
        match ppid_map.entry(record.ppid) {
            Vacant(entry) => { entry.insert(vec![record.pid]); },
            Occupied(mut entry) => { entry.get_mut().push(record.pid); },
        };
    }

    // With the data structures built, it is off to the races
    populate_node_helper(node, &pid_map, &ppid_map);
}

fn build_process_tree() -> ProcessTree {
    let records = get_process_records();
    let mut tree = ProcessTree {
        root : ProcessTreeNode::new(
            &ProcessRecord {
                name: "/".to_string(),
                pid: 0,
                ppid: -1
            })
    };

    // recursively populate all nodes in the tree starting from root (pid 0)
    {
        let root = &mut tree.root;
        populate_node(root, &records);
    }
    tree
}

fn print_node(node : &ProcessTreeNode, indent_level : i32) {
    // print indentation
    for _ in (0..indent_level) {
        print!("  ");
    }
    println!("- {} #{}", node.record.name, node.record.pid);
    for child in node.children.iter() {
        print_node(child, indent_level + 1);  // recurse
    }
}

fn main() {
    let ptree = build_process_tree();
    print_node(&(ptree.root), 0)
}
<|endoftext|>