<commit_before>pub use winit::os::unix::x11::{XError, XNotSupported, XConnection};

use std::{mem, ptr, fmt, error};
use std::sync::Arc;

use winit;
use winit::os::unix::{WindowExt, get_x11_xconnection};

use {Api, ContextError, CreationError, GlAttributes, GlRequest, PixelFormat, PixelFormatRequirements};

use std::ffi::CString;

use api::glx::{ffi, Context as GlxContext};
use api::{dlopen, egl};
use api::egl::Context as EglContext;
use api::glx::ffi::glx::Glx;
use api::egl::ffi::egl::Egl;

#[derive(Debug)]
struct NoX11Connection;

impl error::Error for NoX11Connection {
    fn description(&self) -> &str {
        "failed to get x11 connection"
    }
}

impl fmt::Display for NoX11Connection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(error::Error::description(self))
    }
}

struct GlxOrEgl {
    glx: Option<Glx>,
    egl: Option<Egl>,
}

impl GlxOrEgl {
    fn new() -> GlxOrEgl {
        // TODO: use something safer than raw "dlopen"
        let glx = {
            let mut libglx = unsafe {
                dlopen::dlopen(b"libGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libglx.is_null() {
                libglx = unsafe {
                    dlopen::dlopen(b"libGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libglx.is_null() {
                None
            } else {
                Some(Glx::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libglx, sym.as_ptr()) }
                }))
            }
        };
        // TODO: use something safer than raw "dlopen"
        let egl = {
            let mut libegl = unsafe {
                dlopen::dlopen(b"libEGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libegl.is_null() {
                libegl = unsafe {
                    dlopen::dlopen(b"libEGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libegl.is_null() {
                None
            } else {
                Some(Egl::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libegl, sym.as_ptr()) }
                }))
            }
        };
        GlxOrEgl {
            glx: glx,
            egl: egl,
        }
    }
}

enum GlContext {
    Glx(GlxContext),
    Egl(EglContext),
    None,
}

pub struct Context {
    display: Arc<XConnection>,
    colormap: ffi::Colormap,
    context: GlContext,
}

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            // we don't call MakeCurrent(0, 0) because we are not sure that the context
            // is still the current one
            self.context = GlContext::None;

            (self.display.xlib.XFreeColormap)(self.display.display, self.colormap);
        }
    }
}

impl Context {

    pub fn new(
        window: &winit::Window,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<Self, CreationError>
    {
        let display = match get_x11_xconnection() {
            Some(display) => display,
            None => return Err(CreationError::NoBackendAvailable(Box::new(NoX11Connection))),
        };

        // Get the screen_id for the current window.
        //
        // TODO: re-add this when the `get_monitor_id` method is added.
        // let screen_id = match window.get_monitor_id().get_native_identifier() {
        //     winit::NativeMonitorId::Numeric(monitor) => monitor as i32,
        //     _ => unreachable!(),
        // };
        let screen_id = unsafe { (display.xlib.XDefaultScreen)(display.display) };

        // start the context building process
        enum Prototype<'a> {
            Glx(::api::glx::ContextPrototype<'a>),
            Egl(::api::egl::ContextPrototype<'a>),
        }

        let builder_clone_opengl_glx = gl_attr.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let builder_clone_opengl_egl = gl_attr.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let backend = GlxOrEgl::new();
        let context = match gl_attr.version {
            GlRequest::Latest |
            GlRequest::Specific(Api::OpenGl, _) |
            GlRequest::GlThenGles { .. } => {
                // GLX should be preferred over EGL, otherwise crashes may occur
                // on X11 – issue #314
                if let Some(ref glx) = backend.glx {
                    Prototype::Glx(try!(GlxContext::new(
                        glx.clone(),
                        &display.xlib,
                        pf_reqs,
                        &builder_clone_opengl_glx,
                        display.display,
                        screen_id,
                        gl_attr.transparent,
                    )))
                } else if let Some(ref egl) = backend.egl {
                    let native_display = egl::NativeDisplay::X11(Some(display.display as *const _));
                    Prototype::Egl(try!(EglContext::new(
                        egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        native_display,
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(Api::OpenGlEs, _) => {
                if let Some(ref egl) = backend.egl {
                    Prototype::Egl(try!(EglContext::new(
                        egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        egl::NativeDisplay::X11(Some(display.display as *const _)),
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(_, _) => {
                return Err(CreationError::NotSupported);
            },
        };

        // getting the `visual_infos` (a struct that contains information about the visual to use)
        let visual_infos = match context {
            Prototype::Glx(ref p) => p.get_visual_infos().clone(),
            Prototype::Egl(ref p) => {
                unsafe {
                    let mut template: ffi::XVisualInfo = mem::zeroed();
                    template.visualid = p.get_native_visual_id() as ffi::VisualID;

                    let mut num_visuals = 0;
                    let vi = (display.xlib.XGetVisualInfo)(display.display, ffi::VisualIDMask,
                                                           &mut template, &mut num_visuals);
                    display.check_errors().expect("Failed to call XGetVisualInfo");
                    assert!(!vi.is_null());
                    assert!(num_visuals == 1);

                    let vi_copy = ptr::read(vi as *const _);
                    (display.xlib.XFree)(vi as *mut _);
                    vi_copy
                }
            },
        };

        let xlib_window = window.get_xlib_window().unwrap();
        // finish creating the OpenGL context
        let context = match context {
            Prototype::Glx(ctxt) => {
                GlContext::Glx(try!(ctxt.finish(xlib_window as _)))
            },
            Prototype::Egl(ctxt) => {
                GlContext::Egl(try!(ctxt.finish(xlib_window)))
            },
        };

        // getting the root window
        let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
        display.check_errors().expect("Failed to get root window");

        // creating the color map
        let cmap = unsafe {
            let cmap = (display.xlib.XCreateColormap)(display.display, root,
                                                      visual_infos.visual as *mut _,
                                                      ffi::AllocNone);
            display.check_errors().expect("Failed to call XCreateColormap");
            cmap
        };

        Ok(Context {
            display: display.clone(),
            context: context,
            colormap: cmap,
        })
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.make_current(),
            GlContext::Egl(ref ctxt) => ctxt.make_current(),
            GlContext::None => Ok(())
        }
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.is_current(),
            GlContext::Egl(ref ctxt) => ctxt.is_current(),
            GlContext::None => panic!()
        }
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.get_proc_address(addr),
            GlContext::Egl(ref ctxt) => ctxt.get_proc_address(addr),
            GlContext::None => ptr::null()
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.swap_buffers(),
            GlContext::Egl(ref ctxt) => ctxt.swap_buffers(),
            GlContext::None => Ok(())
        }
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.get_api(),
            GlContext::Egl(ref ctxt) => ctxt.get_api(),
            GlContext::None => panic!()
        }
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.get_pixel_format(),
            GlContext::Egl(ref ctxt) => ctxt.get_pixel_format(),
            GlContext::None => panic!()
        }
    }
}
<commit_msg>Implement missing screen_id code in x11 backend<commit_after>pub use winit::os::unix::x11::{XError, XNotSupported, XConnection};

use std::{mem, ptr, fmt, error};
use std::sync::Arc;

use winit;
use winit::os::unix::{WindowExt, get_x11_xconnection};

use {Api, ContextError, CreationError, GlAttributes, GlRequest, PixelFormat, PixelFormatRequirements};

use std::ffi::CString;

use api::glx::{ffi, Context as GlxContext};
use api::{dlopen, egl};
use api::egl::Context as EglContext;
use api::glx::ffi::glx::Glx;
use api::egl::ffi::egl::Egl;

#[derive(Debug)]
struct NoX11Connection;

impl error::Error for NoX11Connection {
    fn description(&self) -> &str {
        "failed to get x11 connection"
    }
}

impl fmt::Display for NoX11Connection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(error::Error::description(self))
    }
}

struct GlxOrEgl {
    glx: Option<Glx>,
    egl: Option<Egl>,
}

impl GlxOrEgl {
    fn new() -> GlxOrEgl {
        // TODO: use something safer than raw "dlopen"
        let glx = {
            let mut libglx = unsafe {
                dlopen::dlopen(b"libGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libglx.is_null() {
                libglx = unsafe {
                    dlopen::dlopen(b"libGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libglx.is_null() {
                None
            } else {
                Some(Glx::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libglx, sym.as_ptr()) }
                }))
            }
        };
        // TODO: use something safer than raw "dlopen"
        let egl = {
            let mut libegl = unsafe {
                dlopen::dlopen(b"libEGL.so.1\0".as_ptr() as *const _, dlopen::RTLD_NOW)
            };
            if libegl.is_null() {
                libegl = unsafe {
                    dlopen::dlopen(b"libEGL.so\0".as_ptr() as *const _, dlopen::RTLD_NOW)
                };
            }
            if libegl.is_null() {
                None
            } else {
                Some(Egl::load_with(|sym| {
                    let sym = CString::new(sym).unwrap();
                    unsafe { dlopen::dlsym(libegl, sym.as_ptr()) }
                }))
            }
        };
        GlxOrEgl {
            glx: glx,
            egl: egl,
        }
    }
}

enum GlContext {
    Glx(GlxContext),
    Egl(EglContext),
    None,
}

pub struct Context {
    display: Arc<XConnection>,
    colormap: ffi::Colormap,
    context: GlContext,
}

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            // we don't call MakeCurrent(0, 0) because we are not sure that the context
            // is still the current one
            self.context = GlContext::None;

            (self.display.xlib.XFreeColormap)(self.display.display, self.colormap);
        }
    }
}

impl Context {

    pub fn new(
        window: &winit::Window,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<Self, CreationError>
    {
        let display = match get_x11_xconnection() {
            Some(display) => display,
            None => return Err(CreationError::NoBackendAvailable(Box::new(NoX11Connection))),
        };

        // Get the screen_id for the current window.
        let screen_id = window.get_xlib_screen_id().expect("expected x11 window") as i32;

        // start the context building process
        enum Prototype<'a> {
            Glx(::api::glx::ContextPrototype<'a>),
            Egl(::api::egl::ContextPrototype<'a>),
        }

        let builder_clone_opengl_glx = gl_attr.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let builder_clone_opengl_egl = gl_attr.clone().map_sharing(|_| unimplemented!());      // FIXME:
        let backend = GlxOrEgl::new();
        let context = match gl_attr.version {
            GlRequest::Latest |
            GlRequest::Specific(Api::OpenGl, _) |
            GlRequest::GlThenGles { .. } => {
                // GLX should be preferred over EGL, otherwise crashes may occur
                // on X11 – issue #314
                if let Some(ref glx) = backend.glx {
                    Prototype::Glx(try!(GlxContext::new(
                        glx.clone(),
                        &display.xlib,
                        pf_reqs,
                        &builder_clone_opengl_glx,
                        display.display,
                        screen_id,
                        gl_attr.transparent,
                    )))
                } else if let Some(ref egl) = backend.egl {
                    let native_display = egl::NativeDisplay::X11(Some(display.display as *const _));
                    Prototype::Egl(try!(EglContext::new(
                        egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        native_display,
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(Api::OpenGlEs, _) => {
                if let Some(ref egl) = backend.egl {
                    Prototype::Egl(try!(EglContext::new(
                        egl.clone(),
                        pf_reqs,
                        &builder_clone_opengl_egl,
                        egl::NativeDisplay::X11(Some(display.display as *const _)),
                    )))
                } else {
                    return Err(CreationError::NotSupported);
                }
            },
            GlRequest::Specific(_, _) => {
                return Err(CreationError::NotSupported);
            },
        };

        // getting the `visual_infos` (a struct that contains information about the visual to use)
        let visual_infos = match context {
            Prototype::Glx(ref p) => p.get_visual_infos().clone(),
            Prototype::Egl(ref p) => {
                unsafe {
                    let mut template: ffi::XVisualInfo = mem::zeroed();
                    template.visualid = p.get_native_visual_id() as ffi::VisualID;

                    let mut num_visuals = 0;
                    let vi = (display.xlib.XGetVisualInfo)(display.display, ffi::VisualIDMask,
                                                           &mut template, &mut num_visuals);
                    display.check_errors().expect("Failed to call XGetVisualInfo");
                    assert!(!vi.is_null());
                    assert!(num_visuals == 1);

                    let vi_copy = ptr::read(vi as *const _);
                    (display.xlib.XFree)(vi as *mut _);
                    vi_copy
                }
            },
        };

        let xlib_window = window.get_xlib_window().unwrap();
        // finish creating the OpenGL context
        let context = match context {
            Prototype::Glx(ctxt) => {
                GlContext::Glx(try!(ctxt.finish(xlib_window as _)))
            },
            Prototype::Egl(ctxt) => {
                GlContext::Egl(try!(ctxt.finish(xlib_window)))
            },
        };

        // getting the root window
        let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
        display.check_errors().expect("Failed to get root window");

        // creating the color map
        let cmap = unsafe {
            let cmap = (display.xlib.XCreateColormap)(display.display, root,
                                                      visual_infos.visual as *mut _,
                                                      ffi::AllocNone);
            display.check_errors().expect("Failed to call XCreateColormap");
            cmap
        };

        Ok(Context {
            display: display.clone(),
            context: context,
            colormap: cmap,
        })
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.make_current(),
            GlContext::Egl(ref ctxt) => ctxt.make_current(),
            GlContext::None => Ok(())
        }
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.is_current(),
            GlContext::Egl(ref ctxt) => ctxt.is_current(),
            GlContext::None => panic!()
        }
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.get_proc_address(addr),
            GlContext::Egl(ref ctxt) => ctxt.get_proc_address(addr),
            GlContext::None => ptr::null()
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.swap_buffers(),
            GlContext::Egl(ref ctxt) => ctxt.swap_buffers(),
            GlContext::None => Ok(())
        }
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.get_api(),
            GlContext::Egl(ref ctxt) => ctxt.get_api(),
            GlContext::None => panic!()
        }
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        match self.context {
            GlContext::Glx(ref ctxt) => ctxt.get_pixel_format(),
            GlContext::Egl(ref ctxt) => ctxt.get_pixel_format(),
            GlContext::None => panic!()
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate numbat;

use std::mem::zeroed;
use std::ffi::CString;
use forza;

fn get_disk_usage(mountpoint: &str) -> Result<f64, String> {
  unsafe {
    let mut stats: libc::statvfs = zeroed();
    match libc::statvfs(CString::new(mountpoint).unwrap().as_ptr(), &mut stats) {
      -1 => Err(String::from("statvfs() failed")),
      _ => {
        let total = stats.f_blocks * stats.f_frsize;
        let used = total - (stats.f_bavail * stats.f_bsize);
        Ok(used as f64 / total as f64)
      }
    }
  }
}

pub struct DiskUsage<'a> {
  emitter: numbat::Emitter<'a>,
}

impl<'a> DiskUsage<'a> {
  pub fn new(emitter: numbat::Emitter<'a>) -> DiskUsage {
    DiskUsage {
      emitter: emitter
    }
  }

  fn send(&mut self) {
    let ret = get_disk_usage("/");
    match ret {
      Ok(usage) => {
        self.emitter.emit("disk-usage", usage);
      },
      Err(e) => panic!("statvfs() failed: {}", e)
    }

  }
}

impl<'a> forza::ForzaPlugin for DiskUsage<'a> {
  fn start(&mut self) {
    println!("starting disk usage plugin");
    forza::schedule_repeating(move || {
      self.send();
    }, 120);
  }
}
<commit_msg>feat: send disk usage for / and /mnt<commit_after>extern crate libc;
extern crate numbat;

use std::mem::zeroed;
use std::ffi::CString;
use forza;

fn get_disk_usage(mountpoint: &str) -> Result<f64, String> {
  unsafe {
    let mut stats: libc::statvfs = zeroed();
    match libc::statvfs(CString::new(mountpoint).unwrap().as_ptr(), &mut stats) {
      -1 => Err(String::from("statvfs() failed")),
      _ => {
        let total = stats.f_blocks * stats.f_frsize;
        let used = total - (stats.f_bavail * stats.f_bsize);
        Ok(used as f64 / total as f64)
      }
    }
  }
}

pub struct DiskUsage<'a> {
  emitter: numbat::Emitter<'a>,
}

impl<'a> DiskUsage<'a> {
  pub fn new(emitter: numbat::Emitter<'a>) -> DiskUsage {
    DiskUsage {
      emitter: emitter
    }
  }

  fn send(&mut self) {
    self.send_for_mountpoint("/");
    self.send_for_mountpoint("/mnt");
  }

  fn send_for_mountpoint(&mut self, mountpoint: &str) {
    let usage = get_disk_usage(mountpoint);
    if usage.is_ok() {
      self.emitter.emit(&(String::from("disk-usage.") + mountpoint), usage.unwrap());
    }
  }
}

impl<'a> forza::ForzaPlugin for DiskUsage<'a> {
  fn start(&mut self) {
    println!("starting disk usage plugin");
    forza::schedule_repeating(move || {
      self.send();
    }, 120);
  }
}
<|endoftext|>


<commit_before>use {Distribution, Generator};

/// A continuous uniform distribution.
#[derive(Clone, Copy)]
pub struct Uniform {
    /// The left endpoint of the support.
    pub a: f64,
    /// The right endpoint of the support.
    pub b: f64,
}

impl Uniform {
    /// Create a uniform distribution on the interval `[a, b]`.
    ///
    /// # Panics
    ///
    /// Panics if `a >= b`.
    #[inline]
    pub fn new(a: f64, b: f64) -> Uniform {
        debug_assert!(a < b, "Uniform::new() is called with a >= b");
        Uniform { a: a, b: b }
    }
}

impl Distribution for Uniform {
    type Item = f64;

    #[inline]
    fn cdf(&self, x: f64) -> f64 {
        if x <= self.a {
            0.0
        } else if self.b <= x {
            1.0
        } else {
            (x - self.a) / (self.b - self.a)
        }
    }

    #[inline]
    fn inv_cdf(&self, p: f64) -> f64 {
        debug_assert!(0.0 <= p && p <= 1.0, "inv_cdf is called with p outside of [0, 1]");
        self.a + (self.b - self.a) * p
    }

    #[inline]
    fn pdf(&self, x: f64) -> f64 {
        if x < self.a || x > self.b {
            0.0
        } else {
            1.0 / (self.b - self.a)
        }
    }

    #[inline]
    fn sample<G: Generator>(&self, generator: &mut G) -> f64 {
        self.a + (self.b - self.a) * generator.gen::<f64>()
    }
}

#[cfg(test)]
mod tests {
    use {Distribution, Sampler};
    use distributions::Uniform;

    #[test]
    #[should_panic]
    #[allow(unused_variables)]
    fn invalid_support() {
        let uniform = Uniform::new(2.0, -1.0);
    }

    #[test]
    fn pdf() {
        let uniform = Uniform::new(-1.0, 1.0);
        let x = vec![-1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5];
        let p = vec![0.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.0];

        assert_eq!(x.iter().map(|&x| uniform.pdf(x)).collect::<Vec<_>>(), p);
    }

    #[test]
    fn cdf() {
        let uniform = Uniform::new(-1.0, 1.0);
        let x = vec![-1.0, -0.5, 0.0, 0.5, 1.0];
        let p = vec![0.0, 0.25, 0.5, 0.75, 1.0];

        assert_eq!(x.iter().map(|&x| uniform.cdf(x)).collect::<Vec<_>>(), p);
    }

    #[test]
    fn inv_cdf() {
        let uniform = Uniform::new(-1.0, 1.0);
        let x = vec![-1.0, -0.5, 0.0, 0.5, 1.0];
        let p = vec![0.0, 0.25, 0.5, 0.75, 1.0];

        assert_eq!(p.iter().map(|&p| uniform.inv_cdf(p)).collect::<Vec<_>>(), x);
    }

    #[test]
    fn sample() {
        let mut generator = ::generator();
        let uniform = Uniform::new(7.0, 42.0);

        for x in Sampler(&uniform, &mut generator).take(100) {
            assert!(7.0 <= x && x <= 42.0);
        }
    }
}
<commit_msg>Make use of the assert crate<commit_after>use {Distribution, Generator};

/// A continuous uniform distribution.
#[derive(Clone, Copy)]
pub struct Uniform {
    /// The left endpoint of the support.
    pub a: f64,
    /// The right endpoint of the support.
    pub b: f64,
}

impl Uniform {
    /// Create a uniform distribution on the interval `[a, b]`.
    ///
    /// # Panics
    ///
    /// Panics if `a >= b`.
    #[inline]
    pub fn new(a: f64, b: f64) -> Uniform {
        debug_assert!(a < b, "Uniform::new() is called with a >= b");
        Uniform { a: a, b: b }
    }
}

impl Distribution for Uniform {
    type Item = f64;

    #[inline]
    fn cdf(&self, x: f64) -> f64 {
        if x <= self.a {
            0.0
        } else if self.b <= x {
            1.0
        } else {
            (x - self.a) / (self.b - self.a)
        }
    }

    #[inline]
    fn inv_cdf(&self, p: f64) -> f64 {
        debug_assert!(0.0 <= p && p <= 1.0, "inv_cdf is called with p outside of [0, 1]");
        self.a + (self.b - self.a) * p
    }

    #[inline]
    fn pdf(&self, x: f64) -> f64 {
        if x < self.a || x > self.b {
            0.0
        } else {
            1.0 / (self.b - self.a)
        }
    }

    #[inline]
    fn sample<G: Generator>(&self, generator: &mut G) -> f64 {
        self.a + (self.b - self.a) * generator.gen::<f64>()
    }
}

#[cfg(test)]
mod tests {
    use assert;

    use {Distribution, Sampler};
    use distributions::Uniform;

    #[test]
    #[should_panic]
    #[allow(unused_variables)]
    fn invalid_support() {
        let uniform = Uniform::new(2.0, -1.0);
    }

    #[test]
    fn pdf() {
        let uniform = Uniform::new(-1.0, 1.0);
        let x = vec![-1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5];
        let p = vec![0.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.0];

        assert::equal(&x.iter().map(|&x| uniform.pdf(x)).collect::<Vec<_>>(), &p);
    }

    #[test]
    fn cdf() {
        let uniform = Uniform::new(-1.0, 1.0);
        let x = vec![-1.0, -0.5, 0.0, 0.5, 1.0];
        let p = vec![0.0, 0.25, 0.5, 0.75, 1.0];

        assert::equal(&x.iter().map(|&x| uniform.cdf(x)).collect::<Vec<_>>(), &p);
    }

    #[test]
    fn inv_cdf() {
        let uniform = Uniform::new(-1.0, 1.0);
        let x = vec![-1.0, -0.5, 0.0, 0.5, 1.0];
        let p = vec![0.0, 0.25, 0.5, 0.75, 1.0];

        assert::equal(&p.iter().map(|&p| uniform.inv_cdf(p)).collect::<Vec<_>>(), &x);
    }

    #[test]
    fn sample() {
        let mut generator = ::generator();
        let uniform = Uniform::new(7.0, 42.0);

        for x in Sampler(&uniform, &mut generator).take(100) {
            assert!(7.0 <= x && x <= 42.0);
        }
    }
}
<|endoftext|>


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

use any_pointer;
use MessageSize;
use capability::{Params, Promise, Request, RemotePromise, Results};

pub trait ResponseHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

pub trait RequestHook {
    fn get<'a>(&'a mut self) -> any_pointer::Builder<'a>;
    fn get_brand(&self) -> usize;
    fn send<'a>(self: Box<Self>) -> RemotePromise<any_pointer::Owned>;
    fn tail_send(self: Box<Self>)
                 -> Option<(u32, ::capability::Promise<(), ::Error>, Box<PipelineHook>)>;
}

pub trait ClientHook {
    fn add_ref(&self) -> Box<ClientHook>;
    fn new_call(&self,
                interface_id: u64,
                method_id: u16,
                size_hint: Option<MessageSize>)
                -> Request<any_pointer::Owned, any_pointer::Owned>;

    fn call(&self, interface_id: u64, method_id: u16,
            params: Box<ParamsHook>, results: Box<ResultsHook>,
            results_done: ::capability::Promise<Box<ResultsDoneHook>, ::Error>)
            -> (::capability::Promise<(), ::Error>, Box<PipelineHook>);

    fn get_brand(&self) -> usize;
    fn get_ptr(&self) -> usize;

    fn write_target(&self, target: any_pointer::Builder) -> Option<Box<ClientHook>>;
    fn write_descriptor(&self, descriptor: any_pointer::Builder) -> Option<u32>;
    fn get_innermost_client(&self) -> Box<ClientHook>;

    /// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
    /// of the capability.  The caller may permanently replace this client with the resolved one if
    /// desired.  Returns null if the client isn't a promise or hasn't resolved yet -- use
    /// `whenMoreResolved()` to distinguish between them.
    fn get_resolved(&self) -> Option<Box<ClientHook>>;

    /// If this client is a settled reference (not a promise), return nullptr.  Otherwise, return a
    /// promise that eventually resolves to a new client that is closer to being the final, settled
    /// client (i.e. the value eventually returned by `getResolved()`).  Calling this repeatedly
    /// should eventually produce a settled client.
    fn when_more_resolved(&self) -> Option<::capability::Promise<Box<ClientHook>, ::Error>>;

    /// Repeatedly calls whenMoreResolved() until it returns nullptr.
    fn when_resolved(&self) -> ::capability::Promise<(), ::Error> {
        match self.when_more_resolved() {
            Some(promise) => {
                promise.then(|resolution|{
                    resolution.when_resolved()
                })
            }
            None => {
                Promise::ok(())
            }
        }
    }
}

impl Clone for Box<ClientHook> {
    fn clone(&self) -> Box<ClientHook> {
        self.add_ref()
    }
}

pub trait ServerHook: 'static {
    fn new_client(server: Box<::capability::Server>) -> ::capability::Client;
}

pub trait ResultsHook {
    fn get<'a>(&'a mut self) -> ::Result<any_pointer::Builder<'a>>;
    fn allow_cancellation(&self);
    fn tail_call(self: Box<Self>, request: Box<RequestHook>) -> Promise<(), ::Error>;
    fn direct_tail_call(self: Box<Self>, request: Box<RequestHook>) ->
        (::capability::Promise<(), ::Error>, Box<PipelineHook>);
}

pub trait ResultsDoneHook {
    fn add_ref(&self) -> Box<ResultsDoneHook>;
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

impl Clone for Box<ResultsDoneHook> {
    fn clone(&self) -> Box<ResultsDoneHook> {
        self.add_ref()
    }
}

pub trait ParamsHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

// Where should this live?
pub fn internal_get_typed_params<T>(typeless: Params<any_pointer::Owned>) -> Params<T> {
    Params { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_typed_results<T>(typeless: Results<any_pointer::Owned>) -> Results<T> {
    Results { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_untyped_results<T>(typeful: Results<T>) -> Results<any_pointer::Owned> {
    Results { hook: typeful.hook, marker: ::std::marker::PhantomData }
}

pub trait PipelineHook {
    fn add_ref(&self) -> Box<PipelineHook>;
    fn get_pipelined_cap(&self, ops: &[PipelineOp]) -> Box<ClientHook>;

    /// Version of get_pipelined_cap() passing the array by move. May avoid a copy in some cases.
    /// Default implementation just calls the other version.
    fn get_pipelined_cap_move(&self, ops: Vec<PipelineOp>) -> Box<ClientHook> {
        self.get_pipelined_cap(&ops)
    }
}

impl Clone for Box<PipelineHook> {
    fn clone(&self) -> Box<PipelineHook> {
        self.add_ref()
    }
}

#[derive(Clone, Copy)]
pub enum PipelineOp {
    Noop,
    GetPointerField(u16),
}

<commit_msg>Git rid of downcast-workaround methods in ClientHook. We have a new workaround now.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use any_pointer;
use MessageSize;
use capability::{Params, Promise, Request, RemotePromise, Results};

pub trait ResponseHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

pub trait RequestHook {
    fn get<'a>(&'a mut self) -> any_pointer::Builder<'a>;
    fn get_brand(&self) -> usize;
    fn send<'a>(self: Box<Self>) -> RemotePromise<any_pointer::Owned>;
    fn tail_send(self: Box<Self>)
                 -> Option<(u32, ::capability::Promise<(), ::Error>, Box<PipelineHook>)>;
}

pub trait ClientHook {
    fn add_ref(&self) -> Box<ClientHook>;
    fn new_call(&self,
                interface_id: u64,
                method_id: u16,
                size_hint: Option<MessageSize>)
                -> Request<any_pointer::Owned, any_pointer::Owned>;

    fn call(&self, interface_id: u64, method_id: u16,
            params: Box<ParamsHook>, results: Box<ResultsHook>,
            results_done: ::capability::Promise<Box<ResultsDoneHook>, ::Error>)
            -> (::capability::Promise<(), ::Error>, Box<PipelineHook>);

    fn get_brand(&self) -> usize;
    fn get_ptr(&self) -> usize;

    /// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
    /// of the capability.  The caller may permanently replace this client with the resolved one if
    /// desired.  Returns null if the client isn't a promise or hasn't resolved yet -- use
    /// `whenMoreResolved()` to distinguish between them.
    fn get_resolved(&self) -> Option<Box<ClientHook>>;

    /// If this client is a settled reference (not a promise), return nullptr.  Otherwise, return a
    /// promise that eventually resolves to a new client that is closer to being the final, settled
    /// client (i.e. the value eventually returned by `getResolved()`).  Calling this repeatedly
    /// should eventually produce a settled client.
    fn when_more_resolved(&self) -> Option<::capability::Promise<Box<ClientHook>, ::Error>>;

    /// Repeatedly calls whenMoreResolved() until it returns nullptr.
    fn when_resolved(&self) -> ::capability::Promise<(), ::Error> {
        match self.when_more_resolved() {
            Some(promise) => {
                promise.then(|resolution|{
                    resolution.when_resolved()
                })
            }
            None => {
                Promise::ok(())
            }
        }
    }
}

impl Clone for Box<ClientHook> {
    fn clone(&self) -> Box<ClientHook> {
        self.add_ref()
    }
}

pub trait ServerHook: 'static {
    fn new_client(server: Box<::capability::Server>) -> ::capability::Client;
}

pub trait ResultsHook {
    fn get<'a>(&'a mut self) -> ::Result<any_pointer::Builder<'a>>;
    fn allow_cancellation(&self);
    fn tail_call(self: Box<Self>, request: Box<RequestHook>) -> Promise<(), ::Error>;
    fn direct_tail_call(self: Box<Self>, request: Box<RequestHook>) ->
        (::capability::Promise<(), ::Error>, Box<PipelineHook>);
}

pub trait ResultsDoneHook {
    fn add_ref(&self) -> Box<ResultsDoneHook>;
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

impl Clone for Box<ResultsDoneHook> {
    fn clone(&self) -> Box<ResultsDoneHook> {
        self.add_ref()
    }
}

pub trait ParamsHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

// Where should this live?
pub fn internal_get_typed_params<T>(typeless: Params<any_pointer::Owned>) -> Params<T> {
    Params { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_typed_results<T>(typeless: Results<any_pointer::Owned>) -> Results<T> {
    Results { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_untyped_results<T>(typeful: Results<T>) -> Results<any_pointer::Owned> {
    Results { hook: typeful.hook, marker: ::std::marker::PhantomData }
}

pub trait PipelineHook {
    fn add_ref(&self) -> Box<PipelineHook>;
    fn get_pipelined_cap(&self, ops: &[PipelineOp]) -> Box<ClientHook>;

    /// Version of get_pipelined_cap() passing the array by move. May avoid a copy in some cases.
    /// Default implementation just calls the other version.
    fn get_pipelined_cap_move(&self, ops: Vec<PipelineOp>) -> Box<ClientHook> {
        self.get_pipelined_cap(&ops)
    }
}

impl Clone for Box<PipelineHook> {
    fn clone(&self) -> Box<PipelineHook> {
        self.add_ref()
    }
}

#[derive(Clone, Copy)]
pub enum PipelineOp {
    Noop,
    GetPointerField(u16),
}

<|endoftext|>


<commit_before>use std::io;
use super::{Deserialize, Serialize, Error, VarUint7, VarUint32};

/// Internal reference of the exported entry.
#[derive(Debug, Clone, Copy)]
pub enum Internal {
    /// Function reference.
    Function(u32),
    /// Table reference.
    Table(u32),
    /// Memory reference.
    Memory(u32),
    /// Global reference.
    Global(u32),
}

impl Deserialize for Internal {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let kind = VarUint7::deserialize(reader)?;
        match kind.into() {
            0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())),
            0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())),
            0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())),
            0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())),
            _ => Err(Error::UnknownInternalKind(kind.into())),
        }
    }
}

impl Serialize for Internal {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        let (bt, arg) = match self {
            Internal::Function(arg) => (0x00, arg),
            Internal::Table(arg) => (0x01, arg),
            Internal::Memory(arg) => (0x02, arg),
            Internal::Global(arg) => (0x03, arg),
        };

        VarUint7::from(bt).serialize(writer)?;
        VarUint32::from(arg).serialize(writer)?;

        Ok(())
    }
}

/// Export entry.
#[derive(Debug, Clone)]
pub struct ExportEntry {
    field_str: String,
    internal: Internal,
}

impl ExportEntry {
    /// New export entry
    pub fn new(field: String, internal: Internal) -> Self {
        ExportEntry {
            field_str: field,
            internal: internal
        }
    }

    /// Public name
    pub fn field(&self) -> &str { &self.field_str }

    /// Public name (mutable)
    pub fn field_mut(&mut self) -> &mut str { &mut self.field_str }

    /// Internal reference of the export entry.
    pub fn internal(&self) -> &Internal { &self.internal }

    /// Internal reference of the export entry (mutable).
    pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal }
}

impl Deserialize for ExportEntry {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let field_str = String::deserialize(reader)?;
        let internal = Internal::deserialize(reader)?;

        Ok(ExportEntry {
            field_str: field_str,
            internal: internal,
        })
    }
}

impl Serialize for ExportEntry {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.field_str.serialize(writer)?;
        self.internal.serialize(writer)?;
        Ok(())
    }
}
<commit_msg>field_mut better return &mut String<commit_after>use std::io;
use super::{Deserialize, Serialize, Error, VarUint7, VarUint32};

/// Internal reference of the exported entry.
#[derive(Debug, Clone, Copy)]
pub enum Internal {
    /// Function reference.
    Function(u32),
    /// Table reference.
    Table(u32),
    /// Memory reference.
    Memory(u32),
    /// Global reference.
    Global(u32),
}

impl Deserialize for Internal {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let kind = VarUint7::deserialize(reader)?;
        match kind.into() {
            0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())),
            0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())),
            0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())),
            0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())),
            _ => Err(Error::UnknownInternalKind(kind.into())),
        }
    }
}

impl Serialize for Internal {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        let (bt, arg) = match self {
            Internal::Function(arg) => (0x00, arg),
            Internal::Table(arg) => (0x01, arg),
            Internal::Memory(arg) => (0x02, arg),
            Internal::Global(arg) => (0x03, arg),
        };

        VarUint7::from(bt).serialize(writer)?;
        VarUint32::from(arg).serialize(writer)?;

        Ok(())
    }
}

/// Export entry.
#[derive(Debug, Clone)]
pub struct ExportEntry {
    field_str: String,
    internal: Internal,
}

impl ExportEntry {
    /// New export entry
    pub fn new(field: String, internal: Internal) -> Self {
        ExportEntry {
            field_str: field,
            internal: internal
        }
    }

    /// Public name
    pub fn field(&self) -> &str { &self.field_str }

    /// Public name (mutable)
    pub fn field_mut(&mut self) -> &mut String { &mut self.field_str }

    /// Internal reference of the export entry.
    pub fn internal(&self) -> &Internal { &self.internal }

    /// Internal reference of the export entry (mutable).
    pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal }
}

impl Deserialize for ExportEntry {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let field_str = String::deserialize(reader)?;
        let internal = Internal::deserialize(reader)?;

        Ok(ExportEntry {
            field_str: field_str,
            internal: internal,
        })
    }
}

impl Serialize for ExportEntry {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.field_str.serialize(writer)?;
        self.internal.serialize(writer)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io;
use super::{
    Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
    ValueType
};

/// Global definition struct
pub struct GlobalType {
    content_type: ValueType,
    is_mutable: bool,
}

impl GlobalType {
    /// New global type
    pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
        GlobalType {
            content_type: content_type,
            is_mutable: is_mutable,
        }
    }

    /// Type of the global entry
    pub fn content_type(&self) -> ValueType { self.content_type }

    /// Is global entry is declared as mutable
    pub fn is_mutable(&self) -> bool { self.is_mutable }
}

impl Deserialize for GlobalType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let content_type = ValueType::deserialize(reader)?;
        let is_mutable = VarUint1::deserialize(reader)?;
        Ok(GlobalType {
            content_type: content_type,
            is_mutable: is_mutable.into(),
        })
    }
}

impl Serialize for GlobalType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.content_type.serialize(writer)?;
        VarUint1::from(self.is_mutable).serialize(writer)?;
        Ok(())
    }
}

/// Table entry
pub struct TableType {
    elem_type: i8,
    limits: ResizableLimits,
}

impl TableType {
    /// New table definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        TableType {
            elem_type: 0,
            limits: ResizableLimits::new(min, max),
        }
    }
    /// Table memory specification
    pub fn limits(&self) -> &ResizableLimits { &self.limits }
}

impl Deserialize for TableType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let elem_type = VarInt7::deserialize(reader)?;
        let limits = ResizableLimits::deserialize(reader)?;
        Ok(TableType {
            elem_type: elem_type.into(),
            limits: limits,
        })
    }
}

impl Serialize for TableType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        VarInt7::from(self.elem_type).serialize(writer)?;
        self.limits.serialize(writer)
    }
}

/// Memory limits
#[derive(Debug)]
pub struct ResizableLimits {
    initial: u32,
    maximum: Option<u32>,
}

impl ResizableLimits {
    /// New memory limits definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        ResizableLimits {
            initial: min,
            maximum: max,
        }
    }
    /// Initial size
    pub fn initial(&self) -> u32 { self.initial }
    /// Maximum size
    pub fn maximum(&self) -> Option<u32> { self.maximum }
}

impl Deserialize for ResizableLimits {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let has_max = VarUint1::deserialize(reader)?;
        let initial = VarUint32::deserialize(reader)?;
        let maximum = if has_max.into() {
            Some(VarUint32::deserialize(reader)?.into())
        } else {
            None
        };

        Ok(ResizableLimits {
            initial: initial.into(),
            maximum: maximum,
        })
    }
}

impl Serialize for ResizableLimits {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        let max = self.maximum;
        VarUint1::from(max.is_some()).serialize(writer)?;
        VarUint32::from(self.initial).serialize(writer)?;
        if let Some(val) = max {
            VarUint32::from(val).serialize(writer)?;
        }
        Ok(())
    }
}

/// Memory entry.
pub struct MemoryType(ResizableLimits);

impl MemoryType {
    /// New memory definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        MemoryType(ResizableLimits::new(min, max))
    }
    /// Limits of the memory entry.
    pub fn limits(&self) -> &ResizableLimits {
        &self.0
    }
}

impl Deserialize for MemoryType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        Ok(MemoryType(ResizableLimits::deserialize(reader)?))
    }
}

impl Serialize for MemoryType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.0.serialize(writer)
    }
}

/// External to local binding.
pub enum External {
    /// Binds to function with index.
    Function(u32),
    /// Describes local table definition to be imported as.
    Table(TableType),
    /// Describes local memory definition to be imported as.
    Memory(MemoryType),
    /// Describes local global entry to be imported as.
    Global(GlobalType),
}

impl Deserialize for External {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let kind = VarUint7::deserialize(reader)?;
        match kind.into() {
            0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
            0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
            0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
            0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
            _ => Err(Error::UnknownExternalKind(kind.into())),
        }
    }
}

impl Serialize for External {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        use self::External::*;

        match self {
            Function(index) => {
                VarUint7::from(0x00).serialize(writer)?;
                VarUint32::from(index).serialize(writer)?;
            },
            Table(tt) => {
                VarInt7::from(0x01).serialize(writer)?;
                tt.serialize(writer)?;
            },
            Memory(mt) => {
                VarInt7::from(0x02).serialize(writer)?;
                mt.serialize(writer)?;
            },
            Global(gt) => {
                VarInt7::from(0x03).serialize(writer)?;
                gt.serialize(writer)?;
            },
        }

        Ok(())
    }
}

/// Import entry.
pub struct ImportEntry {
    module_str: String,
    field_str: String,
    external: External,
}

impl ImportEntry {
    /// New import entry.
    pub fn new(module_str: String, field_str: String, external: External) -> Self {
        ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        }
    }

    /// Module reference of the import entry.
    pub fn module(&self) -> &str { &self.module_str }

    /// Module reference of the import entry (mutable).
    pub fn module_mut(&mut self) -> &mut str {
        &mut self.module_str
    }

    /// Field reference of the import entry.
    pub fn field(&self) -> &str { &self.field_str }

    /// Field reference of the import entry (mutable)
    pub fn field_mut(&mut self) -> &mut str {
        &mut self.field_str
    }

    /// Local binidng of the import entry.
    pub fn external(&self) -> &External { &self.external }

    /// Local binidng of the import entry (mutable)
    pub fn external_mut(&mut self) -> &External { &mut self.external }
}

impl Deserialize for ImportEntry {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let module_str = String::deserialize(reader)?;
        let field_str = String::deserialize(reader)?;
        let external = External::deserialize(reader)?;

        Ok(ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        })
    }
}

impl Serialize for ImportEntry {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.module_str.serialize(writer)?;
        self.field_str.serialize(writer)?;
        self.external.serialize(writer)
    }
}<commit_msg>mutable signature<commit_after>use std::io;
use super::{
    Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
    ValueType
};

/// Global definition struct
pub struct GlobalType {
    content_type: ValueType,
    is_mutable: bool,
}

impl GlobalType {
    /// New global type
    pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
        GlobalType {
            content_type: content_type,
            is_mutable: is_mutable,
        }
    }

    /// Type of the global entry
    pub fn content_type(&self) -> ValueType { self.content_type }

    /// Is global entry is declared as mutable
    pub fn is_mutable(&self) -> bool { self.is_mutable }
}

impl Deserialize for GlobalType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let content_type = ValueType::deserialize(reader)?;
        let is_mutable = VarUint1::deserialize(reader)?;
        Ok(GlobalType {
            content_type: content_type,
            is_mutable: is_mutable.into(),
        })
    }
}

impl Serialize for GlobalType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.content_type.serialize(writer)?;
        VarUint1::from(self.is_mutable).serialize(writer)?;
        Ok(())
    }
}

/// Table entry
pub struct TableType {
    elem_type: i8,
    limits: ResizableLimits,
}

impl TableType {
    /// New table definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        TableType {
            elem_type: 0,
            limits: ResizableLimits::new(min, max),
        }
    }
    /// Table memory specification
    pub fn limits(&self) -> &ResizableLimits { &self.limits }
}

impl Deserialize for TableType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let elem_type = VarInt7::deserialize(reader)?;
        let limits = ResizableLimits::deserialize(reader)?;
        Ok(TableType {
            elem_type: elem_type.into(),
            limits: limits,
        })
    }
}

impl Serialize for TableType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        VarInt7::from(self.elem_type).serialize(writer)?;
        self.limits.serialize(writer)
    }
}

/// Memory limits
#[derive(Debug)]
pub struct ResizableLimits {
    initial: u32,
    maximum: Option<u32>,
}

impl ResizableLimits {
    /// New memory limits definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        ResizableLimits {
            initial: min,
            maximum: max,
        }
    }
    /// Initial size
    pub fn initial(&self) -> u32 { self.initial }
    /// Maximum size
    pub fn maximum(&self) -> Option<u32> { self.maximum }
}

impl Deserialize for ResizableLimits {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let has_max = VarUint1::deserialize(reader)?;
        let initial = VarUint32::deserialize(reader)?;
        let maximum = if has_max.into() {
            Some(VarUint32::deserialize(reader)?.into())
        } else {
            None
        };

        Ok(ResizableLimits {
            initial: initial.into(),
            maximum: maximum,
        })
    }
}

impl Serialize for ResizableLimits {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        let max = self.maximum;
        VarUint1::from(max.is_some()).serialize(writer)?;
        VarUint32::from(self.initial).serialize(writer)?;
        if let Some(val) = max {
            VarUint32::from(val).serialize(writer)?;
        }
        Ok(())
    }
}

/// Memory entry.
pub struct MemoryType(ResizableLimits);

impl MemoryType {
    /// New memory definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        MemoryType(ResizableLimits::new(min, max))
    }
    /// Limits of the memory entry.
    pub fn limits(&self) -> &ResizableLimits {
        &self.0
    }
}

impl Deserialize for MemoryType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        Ok(MemoryType(ResizableLimits::deserialize(reader)?))
    }
}

impl Serialize for MemoryType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.0.serialize(writer)
    }
}

/// External to local binding.
pub enum External {
    /// Binds to function with index.
    Function(u32),
    /// Describes local table definition to be imported as.
    Table(TableType),
    /// Describes local memory definition to be imported as.
    Memory(MemoryType),
    /// Describes local global entry to be imported as.
    Global(GlobalType),
}

impl Deserialize for External {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let kind = VarUint7::deserialize(reader)?;
        match kind.into() {
            0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
            0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
            0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
            0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
            _ => Err(Error::UnknownExternalKind(kind.into())),
        }
    }
}

impl Serialize for External {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        use self::External::*;

        match self {
            Function(index) => {
                VarUint7::from(0x00).serialize(writer)?;
                VarUint32::from(index).serialize(writer)?;
            },
            Table(tt) => {
                VarInt7::from(0x01).serialize(writer)?;
                tt.serialize(writer)?;
            },
            Memory(mt) => {
                VarInt7::from(0x02).serialize(writer)?;
                mt.serialize(writer)?;
            },
            Global(gt) => {
                VarInt7::from(0x03).serialize(writer)?;
                gt.serialize(writer)?;
            },
        }

        Ok(())
    }
}

/// Import entry.
pub struct ImportEntry {
    module_str: String,
    field_str: String,
    external: External,
}

impl ImportEntry {
    /// New import entry.
    pub fn new(module_str: String, field_str: String, external: External) -> Self {
        ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        }
    }

    /// Module reference of the import entry.
    pub fn module(&self) -> &str { &self.module_str }

    /// Module reference of the import entry (mutable).
    pub fn module_mut(&mut self) -> &mut str {
        &mut self.module_str
    }

    /// Field reference of the import entry.
    pub fn field(&self) -> &str { &self.field_str }

    /// Field reference of the import entry (mutable)
    pub fn field_mut(&mut self) -> &mut str {
        &mut self.field_str
    }

    /// Local binidng of the import entry.
    pub fn external(&self) -> &External { &self.external }

    /// Local binidng of the import entry (mutable)
    pub fn external_mut(&mut self) -> &mut External { &mut self.external }
}

impl Deserialize for ImportEntry {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let module_str = String::deserialize(reader)?;
        let field_str = String::deserialize(reader)?;
        let external = External::deserialize(reader)?;

        Ok(ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        })
    }
}

impl Serialize for ImportEntry {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.module_str.serialize(writer)?;
        self.field_str.serialize(writer)?;
        self.external.serialize(writer)
    }
}<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate duct;

use std::env::{args, current_dir, set_current_dir};
use std::io;
use std::path::Path;
use std::process::exit;

#[cfg(unix)]
fn check_executable(path: &Path) {
    use std::os::unix::fs::MetadataExt;
    const EXECUTABLE_BIT: u32 = 0o100;
    let metadata = path.metadata().unwrap();
    let mode = metadata.mode();
    if mode & EXECUTABLE_BIT == 0 {
        println!(
            "Expected {:?} to be publicly executable, but found mode {:o}.",
            path, mode
        );
        exit(1);
    }
}

#[cfg(windows)]
fn check_executable(_: &Path) {
    // no-op
}

fn main() {
    // The first command line arg is a path to an executable, and the rest are
    // its arguments. Chdir to the parent dir, and then try to execute the
    // program as a single-component Path (*not* a string). Duct should
    // automatically add the leading ./ for us so that it works on Unix. (And if
    // the executable doesn't actually exist, duct should prevent it from
    // matching some other command in the PATH, on either Unix or Windows.)

    let args_vec: Vec<_> = args().collect();
    if args_vec.len() < 2 {
        println!("must have at least 1 exe arg");
        exit(1);
    }

    // Parse out the exe name and the dir it's in.
    let exe_full_path = Path::new(&args_vec[1]);
    let exe_parent = exe_full_path.parent().unwrap();
    let exe_name: &Path = exe_full_path.file_name().unwrap().as_ref();

    // Sanity check that exe actually exists.
    if !exe_full_path.is_file() {
        println!(r#""{}" is not a file."#, exe_full_path.display());
        exit(1);
    }

    // If we try to execute a non-executable file on Unix, we'll end up with a
    // "file not found" error. We really don't want to confuse those with the
    // errors we get from bad Path handling. Explicitly check for that here.
    check_executable(exe_full_path);

    // Chdir to that dir.
    set_current_dir(exe_parent).unwrap();

    // Run the child!
    println!(
        "executing command {:?} in dir {:?}",
        exe_name,
        current_dir().unwrap()
    );
    let res = duct::cmd(exe_name, &args_vec[2..]).run();

    // Check what the child did, and exit appropriately.
    if let Err(err) = res {
        if err.kind() == io::ErrorKind::NotFound {
            println!("File not found during execution! Path sanitization is TOTALLY BROKEN!");
            exit(1);
        } else {
            println!("Unexpected IO error: {:?}", err);
            exit(1);
        }
    } else {
        println!("Success!");
    }
}
<commit_msg>avoid spamming up test output<commit_after>#![deny(warnings)]

extern crate duct;

use std::env::{args, current_dir, set_current_dir};
use std::io;
use std::path::Path;
use std::process::exit;

#[cfg(unix)]
fn check_executable(path: &Path) {
    use std::os::unix::fs::MetadataExt;
    const EXECUTABLE_BIT: u32 = 0o100;
    let metadata = path.metadata().unwrap();
    let mode = metadata.mode();
    if mode & EXECUTABLE_BIT == 0 {
        println!(
            "Expected {:?} to be publicly executable, but found mode {:o}.",
            path, mode
        );
        exit(1);
    }
}

#[cfg(windows)]
fn check_executable(_: &Path) {
    // no-op
}

fn main() {
    // The first command line arg is a path to an executable, and the rest are
    // its arguments. Chdir to the parent dir, and then try to execute the
    // program as a single-component Path (*not* a string). Duct should
    // automatically add the leading ./ for us so that it works on Unix. (And if
    // the executable doesn't actually exist, duct should prevent it from
    // matching some other command in the PATH, on either Unix or Windows.)

    let args_vec: Vec<_> = args().collect();
    if args_vec.len() < 2 {
        println!("must have at least 1 exe arg");
        exit(1);
    }

    // Parse out the exe name and the dir it's in.
    let exe_full_path = Path::new(&args_vec[1]);
    let exe_parent = exe_full_path.parent().unwrap();
    let exe_name: &Path = exe_full_path.file_name().unwrap().as_ref();

    // Sanity check that exe actually exists.
    if !exe_full_path.is_file() {
        println!(r#""{}" is not a file."#, exe_full_path.display());
        exit(1);
    }

    // If we try to execute a non-executable file on Unix, we'll end up with a
    // "file not found" error. We really don't want to confuse those with the
    // errors we get from bad Path handling. Explicitly check for that here.
    check_executable(exe_full_path);

    // Chdir to that dir.
    set_current_dir(exe_parent).unwrap();

    // Run the child!
    let res = duct::cmd(exe_name, &args_vec[2..]).run();

    // Check what the child did, and exit appropriately.
    if let Err(err) = res {
        println!(
            "error executing command {:?} in dir {:?}",
            exe_name,
            current_dir().unwrap()
        );
        if err.kind() == io::ErrorKind::NotFound {
            println!("File not found during execution! Path sanitization is TOTALLY BROKEN!");
            exit(1);
        } else {
            println!("Unexpected IO error: {:?}", err);
            exit(1);
        }
    }

    // Success!
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

use boots::cfg::ControlFlowGraph;
use boots::dfg::DataFlowGraph;

struct Function {
    next_block: usize,
    dfg: DataFlowGraph,
    cfg: ControlFlowGraph,
}

impl Function {
    fn new() -> Function {
        Function {
            next_block: 0,
            dfg: DataFlowGraph::new(),
            cfg: ControlFlowGraph::new(),
        }
    }

    fn make_block(&mut self) -> Block {
        let block = self.next_block;
        self.next_block += 1;
        Block::new(block)
    }
}

#[derive(PartialEq, Eq, Hash)]
pub struct Inst(u32);

impl VecKey for Inst {
    fn new(value: usize) -> Inst {
        Inst(value as u32)
    }

    fn index(&self) -> usize {
        self.0 as usize
    }
}

#[derive(PartialEq, Eq, Hash)]
pub struct Block(u32);

impl VecKey for Block {
    fn new(value: usize) -> Block {
        Block(value as u32)
    }

    fn index(&self) -> usize {
        self.0 as usize
    }
}

pub struct UserList(Vec<Inst>);

impl UserList {
    pub fn new() -> UserList {
        UserList(Vec::new())
    }
}

enum CmpOp {
    Lt,
    Le,
    Eq,
    Ne,
    Gt,
    Ge,
}

pub enum InstData {
    Add {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Sub {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Goto {
        target: Block,
    },

    If {
        opnd: Inst,
        then_block: Block,
        else_block: Block,
    },

    Cmp {
        ty: Type,
        op: CmpOp,
        lhs: Inst,
        rhs: Inst,
    },

    Ret {
        opnd: Option<Inst>,
    },

    TrueConst,
    FalseConst,
    NilConst,
    Int8Const(u8),
    Int32Const(i32),
    Int64Const(i64),
    Float32Const(f32),
    Float64Const(f64),

    Param {
        ty: Type,
        idx: u32,
    },

    Deleted,
}

enum Type {
    Bool,
    Int8,
    Int32,
    Int64,
    Float32,
    Float64,
    Reference,
}

pub struct VecMap<K, V>
where
    K: VecKey,
{
    data: Vec<V>,
    unused: PhantomData<K>,
}

impl<K, V> VecMap<K, V>
where
    K: VecKey,
{
    pub fn new() -> VecMap<K, V> {
        VecMap {
            data: Vec::new(),
            unused: PhantomData,
        }
    }

    pub fn push(&mut self, value: V) -> K {
        let idx = self.data.len();
        self.data.push(value);
        K::new(idx)
    }
}

impl<K, V> Index<K> for VecMap<K, V>
where
    K: VecKey,
{
    type Output = V;

    fn index(&self, k: K) -> &V {
        &self.data[k.index()]
    }
}

impl<K, V> IndexMut<K> for VecMap<K, V>
where
    K: VecKey,
{
    fn index_mut(&mut self, k: K) -> &mut V {
        &mut self.data[k.index()]
    }
}

pub trait VecKey {
    fn new(value: usize) -> Self;
    fn index(&self) -> usize;
}

#[cfg(test)]
mod tests {
    use super::Function;

    #[test]
    fn simple_fn() {
        let mut fct = Function::new();
        let _blk = fct.make_block();
    }
}
<commit_msg>make types public to fix warnings<commit_after>use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

use boots::cfg::ControlFlowGraph;
use boots::dfg::DataFlowGraph;

struct Function {
    next_block: usize,
    dfg: DataFlowGraph,
    cfg: ControlFlowGraph,
}

impl Function {
    fn new() -> Function {
        Function {
            next_block: 0,
            dfg: DataFlowGraph::new(),
            cfg: ControlFlowGraph::new(),
        }
    }

    fn make_block(&mut self) -> Block {
        let block = self.next_block;
        self.next_block += 1;
        Block::new(block)
    }
}

#[derive(PartialEq, Eq, Hash)]
pub struct Inst(u32);

impl VecKey for Inst {
    fn new(value: usize) -> Inst {
        Inst(value as u32)
    }

    fn index(&self) -> usize {
        self.0 as usize
    }
}

#[derive(PartialEq, Eq, Hash)]
pub struct Block(u32);

impl VecKey for Block {
    fn new(value: usize) -> Block {
        Block(value as u32)
    }

    fn index(&self) -> usize {
        self.0 as usize
    }
}

pub struct UserList(Vec<Inst>);

impl UserList {
    pub fn new() -> UserList {
        UserList(Vec::new())
    }
}

pub enum CmpOp {
    Lt,
    Le,
    Eq,
    Ne,
    Gt,
    Ge,
}

pub enum InstData {
    Add {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Sub {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Goto {
        target: Block,
    },

    If {
        opnd: Inst,
        then_block: Block,
        else_block: Block,
    },

    Cmp {
        ty: Type,
        op: CmpOp,
        lhs: Inst,
        rhs: Inst,
    },

    Ret {
        opnd: Option<Inst>,
    },

    TrueConst,
    FalseConst,
    NilConst,
    Int8Const(u8),
    Int32Const(i32),
    Int64Const(i64),
    Float32Const(f32),
    Float64Const(f64),

    Param {
        ty: Type,
        idx: u32,
    },

    Deleted,
}

pub enum Type {
    Bool,
    Int8,
    Int32,
    Int64,
    Float32,
    Float64,
    Reference,
}

pub struct VecMap<K, V>
where
    K: VecKey,
{
    data: Vec<V>,
    unused: PhantomData<K>,
}

impl<K, V> VecMap<K, V>
where
    K: VecKey,
{
    pub fn new() -> VecMap<K, V> {
        VecMap {
            data: Vec::new(),
            unused: PhantomData,
        }
    }

    pub fn push(&mut self, value: V) -> K {
        let idx = self.data.len();
        self.data.push(value);
        K::new(idx)
    }
}

impl<K, V> Index<K> for VecMap<K, V>
where
    K: VecKey,
{
    type Output = V;

    fn index(&self, k: K) -> &V {
        &self.data[k.index()]
    }
}

impl<K, V> IndexMut<K> for VecMap<K, V>
where
    K: VecKey,
{
    fn index_mut(&mut self, k: K) -> &mut V {
        &mut self.data[k.index()]
    }
}

pub trait VecKey {
    fn new(value: usize) -> Self;
    fn index(&self) -> usize;
}

#[cfg(test)]
mod tests {
    use super::Function;

    #[test]
    fn simple_fn() {
        let mut fct = Function::new();
        let _blk = fct.make_block();
    }
}
<|endoftext|>


<commit_before>use crate::{
    models::{Layout, Project},
    ProjectBundle, Targets,
};
use log::trace;
use serde::de::DeserializeOwned;
use std::{
    collections::HashMap,
    default::Default,
    ffi::OsStr,
    fs::{canonicalize, read_dir},
    hash::BuildHasher,
    path::{Path, PathBuf},
};
use thiserror::Error;

pub trait Load: Sized {
    /// Read data from given path into a structure of this type
    fn load(path: impl AsRef<Path>) -> Result<Self, Error>;
}

impl Load for ProjectBundle {
    fn load(bundle_path: impl AsRef<Path>) -> Result<Self, Error> {
        let bundle_path: &Path = bundle_path.as_ref();
        trace!("Loading {:?}", bundle_path);

        Ok(ProjectBundle {
            path: Some(
                canonicalize(&bundle_path).map_err(|source| Error::ReadFile {
                    path: bundle_path.into(),
                    source,
                })?,
            ),
            project: Load::load(&bundle_path.join("project.yaml"))?,
            layouts: Load::load(&bundle_path.join("layouts"))?,
            targets: Load::load(&bundle_path.join("targets"))?,
        })
    }
}

impl Load for Project {
    fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
        let path: &Path = path.as_ref();
        Ok(read_yml(path)?)
    }
}

impl<S: BuildHasher + Default> Load for HashMap<String, Layout, S> {
    fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
        let path: &Path = path.as_ref();
        let yml_files = read_dir(path)
            .map_err(|source| Error::ReadFile {
                path: path.into(),
                source,
            })?
            .filter_map(Result::ok)
            .map(|f| f.path())
            .filter(|p| p.is_file())
            .filter(|p| p.extension() == Some(OsStr::new("yaml")));

        yml_files
            .map(|path| {
                let name = path
                    .file_stem()
                    .ok_or_else(|| Error::MalformedFilename { path: path.clone() })?
                    .to_string_lossy()
                    .to_string();
                let data = read_yml(&path)?;
                Ok((name, data))
            })
            .collect()
    }
}

impl Load for Targets {
    fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
        let path: &Path = path.as_ref();
        Ok(Targets {
            android: read_yml_if_exists(&path.join("android.yaml"))?,
            i_os: read_yml_if_exists(&path.join("ios.yaml"))?,
            mac_os: read_yml_if_exists(&path.join("macos.yaml"))?,
            windows: read_yml_if_exists(&path.join("windows.yaml"))?,
            chrome: read_yml_if_exists(&path.join("chrome.yaml"))?,
            x11: read_yml_if_exists(&path.join("x11.yaml"))?,
            mim: read_yml_if_exists(&path.join("mim.yaml"))?,
        })
    }
}

fn read_yml<T: DeserializeOwned>(path: &Path) -> Result<T, Error> {
    use std::{fs::File, io::BufReader};

    let file = File::open(path).map_err(|source| Error::ReadFile {
        path: path.into(),
        source,
    })?;
    let reader = BufReader::new(file);
    let parsed = serde_yaml::from_reader(reader).map_err(|source| Error::ParseFile {
        path: path.into(),
        source,
    })?;
    Ok(parsed)
}

fn read_yml_if_exists<T: DeserializeOwned>(path: impl AsRef<Path>) -> Result<Option<T>, Error> {
    let path: &Path = path.as_ref();
    if !path.is_file() {
        return Ok(None);
    }
    read_yml(path)
}

#[derive(Debug, Error)]
pub enum Error {
    #[error("Could not read `{}`: {}", path.display(), source)]
    ReadFile {
        path: PathBuf,
        source: std::io::Error,
    },
    #[error("Could not parse file with malfolmed name:: `{}`", path.display())]
    MalformedFilename { path: PathBuf },
    #[error("Could not parse `{}`: {}", path.display(), source)]
    ParseFile {
        path: PathBuf,
        source: serde_yaml::Error,
    },
}
<commit_msg>Load correct target yaml files<commit_after>use crate::{
    models::{Layout, Project},
    ProjectBundle, Targets,
};
use log::trace;
use serde::de::DeserializeOwned;
use std::{
    collections::HashMap,
    default::Default,
    ffi::OsStr,
    fs::{canonicalize, read_dir},
    hash::BuildHasher,
    path::{Path, PathBuf},
};
use thiserror::Error;

pub trait Load: Sized {
    /// Read data from given path into a structure of this type
    fn load(path: impl AsRef<Path>) -> Result<Self, Error>;
}

impl Load for ProjectBundle {
    fn load(bundle_path: impl AsRef<Path>) -> Result<Self, Error> {
        let bundle_path: &Path = bundle_path.as_ref();
        trace!("Loading {:?}", bundle_path);

        Ok(ProjectBundle {
            path: Some(
                canonicalize(&bundle_path).map_err(|source| Error::ReadFile {
                    path: bundle_path.into(),
                    source,
                })?,
            ),
            project: Load::load(&bundle_path.join("project.yaml"))?,
            layouts: Load::load(&bundle_path.join("layouts"))?,
            targets: Load::load(&bundle_path.join("targets"))?,
        })
    }
}

impl Load for Project {
    fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
        let path: &Path = path.as_ref();
        Ok(read_yml(path)?)
    }
}

impl<S: BuildHasher + Default> Load for HashMap<String, Layout, S> {
    fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
        let path: &Path = path.as_ref();
        let yml_files = read_dir(path)
            .map_err(|source| Error::ReadFile {
                path: path.into(),
                source,
            })?
            .filter_map(Result::ok)
            .map(|f| f.path())
            .filter(|p| p.is_file())
            .filter(|p| p.extension() == Some(OsStr::new("yaml")));

        yml_files
            .map(|path| {
                let name = path
                    .file_stem()
                    .ok_or_else(|| Error::MalformedFilename { path: path.clone() })?
                    .to_string_lossy()
                    .to_string();
                let data = read_yml(&path)?;
                Ok((name, data))
            })
            .collect()
    }
}

impl Load for Targets {
    fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
        let path: &Path = path.as_ref();
        Ok(Targets {
            android: read_yml_if_exists(&path.join("android.yaml"))?,
            i_os: read_yml_if_exists(&path.join("ios.yaml"))?,
            mac_os: read_yml_if_exists(&path.join("mac.yaml"))?,
            windows: read_yml_if_exists(&path.join("win.yaml"))?,
            chrome: read_yml_if_exists(&path.join("chrome.yaml"))?,
            x11: read_yml_if_exists(&path.join("x11.yaml"))?,
            mim: read_yml_if_exists(&path.join("mim.yaml"))?,
        })
    }
}

fn read_yml<T: DeserializeOwned>(path: &Path) -> Result<T, Error> {
    use std::{fs::File, io::BufReader};

    let file = File::open(path).map_err(|source| Error::ReadFile {
        path: path.into(),
        source,
    })?;
    let reader = BufReader::new(file);
    let parsed = serde_yaml::from_reader(reader).map_err(|source| Error::ParseFile {
        path: path.into(),
        source,
    })?;
    Ok(parsed)
}

fn read_yml_if_exists<T: DeserializeOwned>(path: impl AsRef<Path>) -> Result<Option<T>, Error> {
    let path: &Path = path.as_ref();
    if !path.is_file() {
        return Ok(None);
    }
    read_yml(path)
}

#[derive(Debug, Error)]
pub enum Error {
    #[error("Could not read `{}`: {}", path.display(), source)]
    ReadFile {
        path: PathBuf,
        source: std::io::Error,
    },
    #[error("Could not parse file with malfolmed name:: `{}`", path.display())]
    MalformedFilename { path: PathBuf },
    #[error("Could not parse `{}`: {}", path.display(), source)]
    ParseFile {
        path: PathBuf,
        source: serde_yaml::Error,
    },
}
<|endoftext|>