<commit_before>use gl;
use glutin;
use native::NativeTaskBuilder;
use std::sync::atomic::{AtomicUint, Relaxed};
use std::sync::{Arc, Mutex};
use std::task::TaskBuilder;
use GliumCreationError;

enum Message {
    EndFrame,
    Execute(proc(&gl::Gl, &mut GLState, &GlVersion, &ExtensionsList):Send),
}

pub struct Context {
    commands: Mutex<Sender<Message>>,
    events: Mutex<Receiver<glutin::Event>>,

    /// Dimensions of the frame buffer.
    dimensions: Arc<(AtomicUint, AtomicUint)>,
}

/// Represents the current OpenGL state.
/// The current state is passed to each function and can be freely updated.
pub struct GLState {
    /// Whether GL_BLEND is enabled
    pub enabled_blend: bool,

    /// Whether GL_CULL_FACE is enabled
    pub enabled_cull_face: bool,

    /// Whether GL_DEBUG_OUTPUT is enabled. None means "unknown".
    pub enabled_debug_output: Option<bool>,

    /// Whether GL_DEBUG_OUTPUT_SYNCHRONOUS is enabled
    pub enabled_debug_output_synchronous: bool,

    /// Whether GL_DEPTH_TEST is enabled
    pub enabled_depth_test: bool,

    /// Whether GL_DITHER is enabled
    pub enabled_dither: bool,

    /// Whether GL_POLYGON_OFFSET_FILL is enabled
    pub enabled_polygon_offset_fill: bool,

    /// Whether GL_SAMPLE_ALPHA_TO_COVERAGE is enabled
    pub enabled_sample_alpha_to_coverage: bool,

    /// Whether GL_SAMPLE_COVERAGE is enabled
    pub enabled_sample_coverage: bool,

    /// Whether GL_SCISSOR_TEST is enabled
    pub enabled_scissor_test: bool,

    /// Whether GL_STENCIL_TEST is enabled
    pub enabled_stencil_test: bool,

    // The latest value passed to `glUseProgram`.
    pub program: gl::types::GLuint,

    // The latest value passed to `glBindVertexArray`.
    pub vertex_array: gl::types::GLuint,

    // The latest value passed to `glClearColor`.
    pub clear_color: (gl::types::GLclampf, gl::types::GLclampf,
                      gl::types::GLclampf, gl::types::GLclampf),

    // The latest value passed to `glClearDepthf`.
    pub clear_depth: gl::types::GLclampf,

    // The latest value passed to `glClearStencil`.
    pub clear_stencil: gl::types::GLint,

    /// The latest buffer bound to `GL_ARRAY_BUFFER`.
    pub array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_ELEMENT_ARRAY_BUFFER`.
    pub element_array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_PIXEL_PACK_BUFFER`.
    pub pixel_pack_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_PIXEL_UNPACK_BUFFER`.
    pub pixel_unpack_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_READ_FRAMEBUFFER`.
    pub read_framebuffer: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_DRAW_FRAMEBUFFER`.
    pub draw_framebuffer: Option<gl::types::GLuint>,

    /// The latest values passed to `glBlendFunc`.
    pub blend_func: (gl::types::GLenum, gl::types::GLenum),

    /// The latest value passed to `glDepthFunc`.
    pub depth_func: gl::types::GLenum,

    /// The latest values passed to `glViewport`.
    pub viewport: (gl::types::GLint, gl::types::GLint, gl::types::GLsizei, gl::types::GLsizei),

    /// The latest value passed to `glLineWidth`.
    pub line_width: gl::types::GLfloat,

    /// The latest value passed to `glCullFace`.
    pub cull_face: gl::types::GLenum,

    /// The latest value passed to `glPolygonMode`.
    pub polygon_mode: gl::types::GLenum,
}

impl GLState {
    /// Builds the `GLState` corresponding to the default GL values.
    fn new_defaults(viewport: (gl::types::GLint, gl::types::GLint, gl::types::GLsizei,
        gl::types::GLsizei)) -> GLState
    {
        GLState {
            enabled_blend: false,
            enabled_cull_face: false,
            enabled_debug_output: None,
            enabled_debug_output_synchronous: false,
            enabled_depth_test: false,
            enabled_dither: false,
            enabled_polygon_offset_fill: false,
            enabled_sample_alpha_to_coverage: false,
            enabled_sample_coverage: false,
            enabled_scissor_test: false,
            enabled_stencil_test: false,

            program: 0,
            vertex_array: 0,
            clear_color: (0.0, 0.0, 0.0, 0.0),
            clear_depth: 1.0,
            clear_stencil: 0,
            array_buffer_binding: None,
            element_array_buffer_binding: None,
            pixel_pack_buffer_binding: None,
            pixel_unpack_buffer_binding: None,
            read_framebuffer: None,
            draw_framebuffer: None,
            depth_func: gl::LESS,
            blend_func: (0, 0),     // no default specified
            viewport: viewport,
            line_width: 1.0,
            cull_face: gl::BACK,
            polygon_mode: gl::FILL,
        }
    }
}

/// Describes an OpenGL version.
#[deriving(Show, Clone, PartialEq, Eq)]
pub struct GlVersion(pub u8, pub u8);

impl PartialOrd for GlVersion {
    fn partial_cmp(&self, other: &GlVersion) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for GlVersion {
    fn cmp(&self, other: &GlVersion) -> Ordering {
        match self.0.cmp(&other.0) {
            Equal => self.1.cmp(&other.1),
            a => a
        }
    }
}

/// Contains data about the list of extensions
pub struct ExtensionsList {
    /// GL_EXT_direct_state_access
    pub gl_ext_direct_state_access: bool,
    /// GL_EXT_framebuffer_object
    pub gl_ext_framebuffer_object: bool,
    /// GL_EXT_geometry_shader4
    pub gl_ext_geometry_shader4: bool,
    /// GL_EXT_framebuffer_blit
    pub gl_ext_framebuffer_blit: bool,
    /// GL_KHR_debug
    pub gl_khr_debug: bool,
}

impl Context {
    pub fn new_from_window(window: glutin::WindowBuilder) -> Result<Context, GliumCreationError> {
        let (tx_events, rx_events) = channel();
        let (tx_commands, rx_commands) = channel();

        let dimensions = Arc::new((AtomicUint::new(800), AtomicUint::new(600)));

        let context = Context {
            commands: Mutex::new(tx_commands),
            events: Mutex::new(rx_events),
            dimensions: dimensions.clone(),
        };

        let (tx_success, rx_success) = channel();

        TaskBuilder::new().native().spawn(proc() {
            // DRIVER-SPECIFIC: creating the window in the same thread as the rendering,
            //                  otherwise ATI X11 drivers fail at `glxMakeCurrent`
            let window = match window.build() {
                Ok(w) => w,
                Err(e) => {
                    tx_success.send(Err(e));
                    return;
                }
            };

            unsafe { window.make_current(); }
            tx_success.send(Ok(()));

            let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));

            // building the GLState and modifying to GL state to match it
            let mut gl_state = {
                let viewport = {
                    let dim = window.get_inner_size().unwrap();
                    dimensions.0.store(dim.0, Relaxed);
                    dimensions.1.store(dim.1, Relaxed);
                    (0, 0, dim.0 as gl::types::GLsizei, dim.1 as gl::types::GLsizei)
                };

                GLState::new_defaults(viewport)
            };

            // getting the GL version and extensions
            let version = get_gl_version(&gl);
            let extensions = get_extensions(&gl);

            // main loop
            'main: loop {
                // processing commands
                loop {
                    match rx_commands.recv_opt() {
                        Ok(EndFrame) => break,
                        Ok(Execute(cmd)) => cmd(&gl, &mut gl_state, &version, &extensions),
                        Err(_) => break 'main
                    }
                }

                // this is necessary on Windows 8, or nothing is being displayed
                unsafe { gl.Flush(); }

                // swapping
                window.swap_buffers();

                // getting events
                for event in window.poll_events() {
                    // calling `glViewport` if the window has been resized
                    if let &glutin::Resized(width, height) = &event {
                        dimensions.0.store(width, Relaxed);
                        dimensions.1.store(height, Relaxed);

                        if gl_state.viewport != (0, 0, width as gl::types::GLsizei,
                                                 height as gl::types::GLsizei)
                        {
                            unsafe {
                                gl.Viewport(0, 0, width as gl::types::GLsizei,
                                    height as gl::types::GLsizei);
                                gl_state.viewport = (0, 0, width as gl::types::GLsizei,
                                    height as gl::types::GLsizei);
                            }
                        }
                    }

                    // sending the event outside
                    if tx_events.send_opt(event.clone()).is_err() {
                        break 'main;
                    }
                }
            }
        });

        try!(rx_success.recv());
        Ok(context)
    }

    pub fn new_from_headless(window: glutin::HeadlessRendererBuilder)
        -> Result<Context, GliumCreationError>
    {
        let (_, rx_events) = channel();
        let (tx_commands, rx_commands) = channel();

        // TODO: fixme
        let dimensions = Arc::new((AtomicUint::new(800), AtomicUint::new(600)));

        let context = Context {
            commands: Mutex::new(tx_commands),
            events: Mutex::new(rx_events),
            dimensions: dimensions,
        };

        let (tx_success, rx_success) = channel();

        TaskBuilder::new().native().spawn(proc() {
            let window = match window.build() {
                Ok(w) => w,
                Err(e) => {
                    tx_success.send(Err(e));
                    return;
                }
            };
            unsafe { window.make_current(); }
            tx_success.send(Ok(()));

            let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));

            // building the GLState, version, and extensions
            let mut gl_state = GLState::new_defaults((0, 0, 0, 0));    // FIXME:
            let version = get_gl_version(&gl);
            let extensions = get_extensions(&gl);

            loop {
                match rx_commands.recv_opt() {
                    Ok(Execute(cmd)) => cmd(&gl, &mut gl_state, &version, &extensions),
                    Ok(EndFrame) => (),     // ignoring buffer swapping
                    Err(_) => break
                }
            }
        });

        try!(rx_success.recv());
        Ok(context)
    }

    pub fn get_framebuffer_dimensions(&self) -> (uint, uint) {
        (
            self.dimensions.0.load(Relaxed),
            self.dimensions.1.load(Relaxed),
        )
    }

    pub fn exec(&self, f: proc(&gl::Gl, &mut GLState, &GlVersion, &ExtensionsList): Send) {
        self.commands.lock().send(Execute(f));
    }

    pub fn swap_buffers(&self) {
        self.commands.lock().send(EndFrame);
    }

    pub fn recv(&self) -> Vec<glutin::Event> {
        let events = self.events.lock();

        let mut result = Vec::new();
        loop {
            match events.try_recv() {
                Ok(ev) => result.push(ev),
                Err(_) => break
            }
        }
        result
    }
}

fn get_gl_version(gl: &gl::Gl) -> GlVersion {
    use std::c_str::CString;

    unsafe {
        let version = gl.GetString(gl::VERSION);
        let version = CString::new(version as *const i8, false);
        let version = version.as_str().expect("OpenGL version contains non-utf8 characters");

        let version = version.words().next().expect("glGetString(GL_VERSION) returned an empty \
                                                     string");

        let mut iter = version.split(|c: char| c == '.');
        let major = iter.next().unwrap();
        let minor = iter.next().expect("glGetString(GL_VERSION) did not return a correct version");

        GlVersion(
            from_str(major).expect("failed to parse GL major version"),
            from_str(minor).expect("failed to parse GL minor version"),
        )
    }
}

fn get_extensions_strings(gl: &gl::Gl) -> Vec<String> {
    use std::c_str::CString;

    unsafe {
        let list = gl.GetString(gl::EXTENSIONS);

        if list.is_null() {
            let mut num_extensions = 0;
            gl.GetIntegerv(gl::NUM_EXTENSIONS, &mut num_extensions);

            range(0, num_extensions).map(|num| {
                let ext = gl.GetStringi(gl::EXTENSIONS, num as gl::types::GLuint);
                let ext = CString::new(ext as *const i8, false);
                ext.as_str().expect("OpenGL extension contains non-utf8 characters").to_string()
            }).collect()

        } else {
            let list = CString::new(list as *const i8, false);
            let list = list.as_str()
                .expect("List of OpenGL extensions contains non-utf8 characters");
            list.words().map(|e| e.to_string()).collect()
        }
    }
}

fn get_extensions(gl: &gl::Gl) -> ExtensionsList {
    let strings = get_extensions_strings(gl);

    let mut extensions = ExtensionsList {
        gl_ext_direct_state_access: false,
        gl_ext_framebuffer_object: false,
        gl_ext_geometry_shader4: false,
        gl_ext_framebuffer_blit: false,
        gl_khr_debug: false,
    };

    for extension in strings.into_iter() {
        match extension.as_slice() {
            "GL_EXT_direct_state_access" => extensions.gl_ext_direct_state_access = true,
            "GL_EXT_framebuffer_object" => extensions.gl_ext_framebuffer_object = true,
            "GL_EXT_geometry_shader4" => extensions.gl_ext_geometry_shader4 = true,
            "GL_EXT_framebuffer_blit" => extensions.gl_ext_framebuffer_blit = true,
            "GL_KHR_debug" => extensions.gl_khr_debug = true,
            _ => ()
        }
    }

    extensions
}
<commit_msg>Remove wrong comment<commit_after>use gl;
use glutin;
use native::NativeTaskBuilder;
use std::sync::atomic::{AtomicUint, Relaxed};
use std::sync::{Arc, Mutex};
use std::task::TaskBuilder;
use GliumCreationError;

enum Message {
    EndFrame,
    Execute(proc(&gl::Gl, &mut GLState, &GlVersion, &ExtensionsList):Send),
}

pub struct Context {
    commands: Mutex<Sender<Message>>,
    events: Mutex<Receiver<glutin::Event>>,

    /// Dimensions of the frame buffer.
    dimensions: Arc<(AtomicUint, AtomicUint)>,
}

/// Represents the current OpenGL state.
/// The current state is passed to each function and can be freely updated.
pub struct GLState {
    /// Whether GL_BLEND is enabled
    pub enabled_blend: bool,

    /// Whether GL_CULL_FACE is enabled
    pub enabled_cull_face: bool,

    /// Whether GL_DEBUG_OUTPUT is enabled. None means "unknown".
    pub enabled_debug_output: Option<bool>,

    /// Whether GL_DEBUG_OUTPUT_SYNCHRONOUS is enabled
    pub enabled_debug_output_synchronous: bool,

    /// Whether GL_DEPTH_TEST is enabled
    pub enabled_depth_test: bool,

    /// Whether GL_DITHER is enabled
    pub enabled_dither: bool,

    /// Whether GL_POLYGON_OFFSET_FILL is enabled
    pub enabled_polygon_offset_fill: bool,

    /// Whether GL_SAMPLE_ALPHA_TO_COVERAGE is enabled
    pub enabled_sample_alpha_to_coverage: bool,

    /// Whether GL_SAMPLE_COVERAGE is enabled
    pub enabled_sample_coverage: bool,

    /// Whether GL_SCISSOR_TEST is enabled
    pub enabled_scissor_test: bool,

    /// Whether GL_STENCIL_TEST is enabled
    pub enabled_stencil_test: bool,

    // The latest value passed to `glUseProgram`.
    pub program: gl::types::GLuint,

    // The latest value passed to `glBindVertexArray`.
    pub vertex_array: gl::types::GLuint,

    // The latest value passed to `glClearColor`.
    pub clear_color: (gl::types::GLclampf, gl::types::GLclampf,
                      gl::types::GLclampf, gl::types::GLclampf),

    // The latest value passed to `glClearDepthf`.
    pub clear_depth: gl::types::GLclampf,

    // The latest value passed to `glClearStencil`.
    pub clear_stencil: gl::types::GLint,

    /// The latest buffer bound to `GL_ARRAY_BUFFER`.
    pub array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_ELEMENT_ARRAY_BUFFER`.
    pub element_array_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_PIXEL_PACK_BUFFER`.
    pub pixel_pack_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_PIXEL_UNPACK_BUFFER`.
    pub pixel_unpack_buffer_binding: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_READ_FRAMEBUFFER`.
    pub read_framebuffer: Option<gl::types::GLuint>,

    /// The latest buffer bound to `GL_DRAW_FRAMEBUFFER`.
    pub draw_framebuffer: Option<gl::types::GLuint>,

    /// The latest values passed to `glBlendFunc`.
    pub blend_func: (gl::types::GLenum, gl::types::GLenum),

    /// The latest value passed to `glDepthFunc`.
    pub depth_func: gl::types::GLenum,

    /// The latest values passed to `glViewport`.
    pub viewport: (gl::types::GLint, gl::types::GLint, gl::types::GLsizei, gl::types::GLsizei),

    /// The latest value passed to `glLineWidth`.
    pub line_width: gl::types::GLfloat,

    /// The latest value passed to `glCullFace`.
    pub cull_face: gl::types::GLenum,

    /// The latest value passed to `glPolygonMode`.
    pub polygon_mode: gl::types::GLenum,
}

impl GLState {
    /// Builds the `GLState` corresponding to the default GL values.
    fn new_defaults(viewport: (gl::types::GLint, gl::types::GLint, gl::types::GLsizei,
        gl::types::GLsizei)) -> GLState
    {
        GLState {
            enabled_blend: false,
            enabled_cull_face: false,
            enabled_debug_output: None,
            enabled_debug_output_synchronous: false,
            enabled_depth_test: false,
            enabled_dither: false,
            enabled_polygon_offset_fill: false,
            enabled_sample_alpha_to_coverage: false,
            enabled_sample_coverage: false,
            enabled_scissor_test: false,
            enabled_stencil_test: false,

            program: 0,
            vertex_array: 0,
            clear_color: (0.0, 0.0, 0.0, 0.0),
            clear_depth: 1.0,
            clear_stencil: 0,
            array_buffer_binding: None,
            element_array_buffer_binding: None,
            pixel_pack_buffer_binding: None,
            pixel_unpack_buffer_binding: None,
            read_framebuffer: None,
            draw_framebuffer: None,
            depth_func: gl::LESS,
            blend_func: (0, 0),     // no default specified
            viewport: viewport,
            line_width: 1.0,
            cull_face: gl::BACK,
            polygon_mode: gl::FILL,
        }
    }
}

/// Describes an OpenGL version.
#[deriving(Show, Clone, PartialEq, Eq)]
pub struct GlVersion(pub u8, pub u8);

impl PartialOrd for GlVersion {
    fn partial_cmp(&self, other: &GlVersion) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for GlVersion {
    fn cmp(&self, other: &GlVersion) -> Ordering {
        match self.0.cmp(&other.0) {
            Equal => self.1.cmp(&other.1),
            a => a
        }
    }
}

/// Contains data about the list of extensions
pub struct ExtensionsList {
    /// GL_EXT_direct_state_access
    pub gl_ext_direct_state_access: bool,
    /// GL_EXT_framebuffer_object
    pub gl_ext_framebuffer_object: bool,
    /// GL_EXT_geometry_shader4
    pub gl_ext_geometry_shader4: bool,
    /// GL_EXT_framebuffer_blit
    pub gl_ext_framebuffer_blit: bool,
    /// GL_KHR_debug
    pub gl_khr_debug: bool,
}

impl Context {
    pub fn new_from_window(window: glutin::WindowBuilder) -> Result<Context, GliumCreationError> {
        let (tx_events, rx_events) = channel();
        let (tx_commands, rx_commands) = channel();

        let dimensions = Arc::new((AtomicUint::new(800), AtomicUint::new(600)));

        let context = Context {
            commands: Mutex::new(tx_commands),
            events: Mutex::new(rx_events),
            dimensions: dimensions.clone(),
        };

        let (tx_success, rx_success) = channel();

        TaskBuilder::new().native().spawn(proc() {
            let window = match window.build() {
                Ok(w) => w,
                Err(e) => {
                    tx_success.send(Err(e));
                    return;
                }
            };

            unsafe { window.make_current(); }
            tx_success.send(Ok(()));

            let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));

            // building the GLState and modifying to GL state to match it
            let mut gl_state = {
                let viewport = {
                    let dim = window.get_inner_size().unwrap();
                    dimensions.0.store(dim.0, Relaxed);
                    dimensions.1.store(dim.1, Relaxed);
                    (0, 0, dim.0 as gl::types::GLsizei, dim.1 as gl::types::GLsizei)
                };

                GLState::new_defaults(viewport)
            };

            // getting the GL version and extensions
            let version = get_gl_version(&gl);
            let extensions = get_extensions(&gl);

            // main loop
            'main: loop {
                // processing commands
                loop {
                    match rx_commands.recv_opt() {
                        Ok(EndFrame) => break,
                        Ok(Execute(cmd)) => cmd(&gl, &mut gl_state, &version, &extensions),
                        Err(_) => break 'main
                    }
                }

                // this is necessary on Windows 8, or nothing is being displayed
                unsafe { gl.Flush(); }

                // swapping
                window.swap_buffers();

                // getting events
                for event in window.poll_events() {
                    // calling `glViewport` if the window has been resized
                    if let &glutin::Resized(width, height) = &event {
                        dimensions.0.store(width, Relaxed);
                        dimensions.1.store(height, Relaxed);

                        if gl_state.viewport != (0, 0, width as gl::types::GLsizei,
                                                 height as gl::types::GLsizei)
                        {
                            unsafe {
                                gl.Viewport(0, 0, width as gl::types::GLsizei,
                                    height as gl::types::GLsizei);
                                gl_state.viewport = (0, 0, width as gl::types::GLsizei,
                                    height as gl::types::GLsizei);
                            }
                        }
                    }

                    // sending the event outside
                    if tx_events.send_opt(event.clone()).is_err() {
                        break 'main;
                    }
                }
            }
        });

        try!(rx_success.recv());
        Ok(context)
    }

    pub fn new_from_headless(window: glutin::HeadlessRendererBuilder)
        -> Result<Context, GliumCreationError>
    {
        let (_, rx_events) = channel();
        let (tx_commands, rx_commands) = channel();

        // TODO: fixme
        let dimensions = Arc::new((AtomicUint::new(800), AtomicUint::new(600)));

        let context = Context {
            commands: Mutex::new(tx_commands),
            events: Mutex::new(rx_events),
            dimensions: dimensions,
        };

        let (tx_success, rx_success) = channel();

        TaskBuilder::new().native().spawn(proc() {
            let window = match window.build() {
                Ok(w) => w,
                Err(e) => {
                    tx_success.send(Err(e));
                    return;
                }
            };
            unsafe { window.make_current(); }
            tx_success.send(Ok(()));

            let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));

            // building the GLState, version, and extensions
            let mut gl_state = GLState::new_defaults((0, 0, 0, 0));    // FIXME:
            let version = get_gl_version(&gl);
            let extensions = get_extensions(&gl);

            loop {
                match rx_commands.recv_opt() {
                    Ok(Execute(cmd)) => cmd(&gl, &mut gl_state, &version, &extensions),
                    Ok(EndFrame) => (),     // ignoring buffer swapping
                    Err(_) => break
                }
            }
        });

        try!(rx_success.recv());
        Ok(context)
    }

    pub fn get_framebuffer_dimensions(&self) -> (uint, uint) {
        (
            self.dimensions.0.load(Relaxed),
            self.dimensions.1.load(Relaxed),
        )
    }

    pub fn exec(&self, f: proc(&gl::Gl, &mut GLState, &GlVersion, &ExtensionsList): Send) {
        self.commands.lock().send(Execute(f));
    }

    pub fn swap_buffers(&self) {
        self.commands.lock().send(EndFrame);
    }

    pub fn recv(&self) -> Vec<glutin::Event> {
        let events = self.events.lock();

        let mut result = Vec::new();
        loop {
            match events.try_recv() {
                Ok(ev) => result.push(ev),
                Err(_) => break
            }
        }
        result
    }
}

fn get_gl_version(gl: &gl::Gl) -> GlVersion {
    use std::c_str::CString;

    unsafe {
        let version = gl.GetString(gl::VERSION);
        let version = CString::new(version as *const i8, false);
        let version = version.as_str().expect("OpenGL version contains non-utf8 characters");

        let version = version.words().next().expect("glGetString(GL_VERSION) returned an empty \
                                                     string");

        let mut iter = version.split(|c: char| c == '.');
        let major = iter.next().unwrap();
        let minor = iter.next().expect("glGetString(GL_VERSION) did not return a correct version");

        GlVersion(
            from_str(major).expect("failed to parse GL major version"),
            from_str(minor).expect("failed to parse GL minor version"),
        )
    }
}

fn get_extensions_strings(gl: &gl::Gl) -> Vec<String> {
    use std::c_str::CString;

    unsafe {
        let list = gl.GetString(gl::EXTENSIONS);

        if list.is_null() {
            let mut num_extensions = 0;
            gl.GetIntegerv(gl::NUM_EXTENSIONS, &mut num_extensions);

            range(0, num_extensions).map(|num| {
                let ext = gl.GetStringi(gl::EXTENSIONS, num as gl::types::GLuint);
                let ext = CString::new(ext as *const i8, false);
                ext.as_str().expect("OpenGL extension contains non-utf8 characters").to_string()
            }).collect()

        } else {
            let list = CString::new(list as *const i8, false);
            let list = list.as_str()
                .expect("List of OpenGL extensions contains non-utf8 characters");
            list.words().map(|e| e.to_string()).collect()
        }
    }
}

fn get_extensions(gl: &gl::Gl) -> ExtensionsList {
    let strings = get_extensions_strings(gl);

    let mut extensions = ExtensionsList {
        gl_ext_direct_state_access: false,
        gl_ext_framebuffer_object: false,
        gl_ext_geometry_shader4: false,
        gl_ext_framebuffer_blit: false,
        gl_khr_debug: false,
    };

    for extension in strings.into_iter() {
        match extension.as_slice() {
            "GL_EXT_direct_state_access" => extensions.gl_ext_direct_state_access = true,
            "GL_EXT_framebuffer_object" => extensions.gl_ext_framebuffer_object = true,
            "GL_EXT_geometry_shader4" => extensions.gl_ext_geometry_shader4 = true,
            "GL_EXT_framebuffer_blit" => extensions.gl_ext_framebuffer_blit = true,
            "GL_KHR_debug" => extensions.gl_khr_debug = true,
            _ => ()
        }
    }

    extensions
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::iter::FromIterator;
use std::error::Error;
use std::convert::From;
use std::num::ParseIntError;
use std::fmt::{self, Display, Formatter};

use schedule::{Schedule, Period, Calendar, ScheduleParseError, PeriodParseError};

#[derive(Debug, PartialEq)]
pub enum CrontabEntry {
    EnvVar(EnvVarEntry),
    User(UserCrontabEntry),
    System(SystemCrontabEntry),
    Anacron(AnacrontabEntry)
}

#[derive(Debug, PartialEq)]
pub struct EnvVarEntry(pub String, pub String);

#[derive(Debug, PartialEq)]
pub struct UserCrontabEntry {
    pub sched: Schedule,
    pub cmd: String
}

#[derive(Debug, PartialEq)]
pub struct SystemCrontabEntry {
    pub sched: Schedule,
    pub user: UserInfo,
    pub cmd: String
}

#[derive(Debug, PartialEq)]
pub struct AnacrontabEntry {
    pub period: Period,
    pub delay: u32,
    pub jobid: String,
    pub cmd: String
}

impl From<UserCrontabEntry> for CrontabEntry {
    fn from(entry: UserCrontabEntry) -> CrontabEntry {
        CrontabEntry::User(entry)
    }
}

impl From<SystemCrontabEntry> for CrontabEntry {
    fn from(entry: SystemCrontabEntry) -> CrontabEntry {
        CrontabEntry::System(entry)
    }
}

impl From<AnacrontabEntry> for CrontabEntry {
    fn from(entry: AnacrontabEntry) -> CrontabEntry {
        CrontabEntry::Anacron(entry)
    }
}

impl From<EnvVarEntry> for CrontabEntry {
    fn from(entry: EnvVarEntry) -> CrontabEntry {
        CrontabEntry::EnvVar(entry)
    }
}

impl Display for CrontabEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            CrontabEntry::EnvVar(ref entry) => entry.fmt(f),
            CrontabEntry::Anacron(ref entry) => entry.fmt(f),
            CrontabEntry::User(ref entry) => entry.fmt(f),
            CrontabEntry::System(ref entry) => entry.fmt(f),
        }
    }
}

impl CrontabEntry {
    pub fn period<'a>(&'a self) -> Option<&'a Period> {
        match *self {
            CrontabEntry::Anacron(AnacrontabEntry { ref period, .. }) => Some(period),
            CrontabEntry::User(UserCrontabEntry { sched: Schedule::Period(ref period), .. }) => Some(period),
            CrontabEntry::System(SystemCrontabEntry { sched: Schedule::Period(ref period), .. }) => Some(period),
            _ => None
        }
    }

    pub fn calendar<'a>(&'a self) -> Option<&'a Calendar> {
        match *self {
            CrontabEntry::User(UserCrontabEntry { sched: Schedule::Calendar(ref cal), .. }) => Some(cal),
            CrontabEntry::System(SystemCrontabEntry { sched: Schedule::Calendar(ref cal), .. }) => Some(cal),
            _ => None
        }
    }

    pub fn command<'a>(&'a self) -> Option<&'a str> {
        match *self {
            CrontabEntry::User(UserCrontabEntry { ref cmd, .. }) => Some(&**cmd),
            CrontabEntry::System(SystemCrontabEntry { ref cmd, .. }) => Some(&**cmd),
            CrontabEntry::Anacron(AnacrontabEntry { ref cmd, .. }) => Some(&**cmd),
            _ => None
        }
    }

    pub fn user<'a>(&'a self) -> Option<&'a str> {
        match *self {
            CrontabEntry::System(SystemCrontabEntry { user: UserInfo(ref user, _, _), .. }) => Some(&**user),
            _ => None
        }
    }

    pub fn group<'a>(&'a self) -> Option<&'a str> {
        match *self {
            CrontabEntry::System(SystemCrontabEntry { user: UserInfo(_, Some(ref group), _), .. }) => Some(&**group),
            _ => None
        }
    }
}

impl Display for EnvVarEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}={}", self.0, self.1)
    }
}

impl FromStr for EnvVarEntry {
    type Err = CrontabEntryParseError;
    fn from_str(s: &str) -> Result<EnvVarEntry, CrontabEntryParseError> {
        let spaces = [' ', '\t'];
        let mut splits = s.splitn(2, '=');

        let name = match splits.next() {
            Some(n) => n.trim_right_matches(&spaces[..]),
            None => return Err(CrontabEntryParseError::MissingEnvVarName)
        };

        if name.len() == 0 {
            return Err(CrontabEntryParseError::MissingEnvVarName)
        }

        if name.chars().any(|v| v == ' ' || v == '\t') {
            return Err(CrontabEntryParseError::InvalidEnvVarName)
        }

        let mut value = match splits.next() {
            Some(v) => v.trim_left_matches(&spaces[..]),
            None => return Err(CrontabEntryParseError::MissingEnvVarValue)
        };

        if value.len() > 1 {
            if &value[..1] == "'" || &value[..1] == "\"" && &value[..1] == &value[value.len()-1..] {
                value = &value[1..value.len()-1];
            }
        }

        Ok(EnvVarEntry(name.to_owned(), value.to_owned()))
    }
}

#[derive(Debug, PartialEq)]
// user, group, class
pub struct UserInfo(pub String, pub Option<String>, pub Option<String>);

#[derive(Debug, PartialEq)]
pub struct UserInfoParseError;

impl Display for UserInfo {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(self.0.fmt(f));
        if let Some(ref group) = self.1 {
            try!(f.write_str(":"));
            try!(group.fmt(f));
        }
        if let Some(ref class) = self.2 {
            try!(f.write_str(":"));
            try!(class.fmt(f));
        }
        Ok(())
    }
}

impl FromStr for UserInfo {
    type Err = UserInfoParseError;
    fn from_str(s: &str) -> Result<UserInfo, UserInfoParseError> {
        let mut splits = s.split(':');
        Ok(UserInfo(
            try!(splits.next().ok_or(UserInfoParseError).map(ToOwned::to_owned)),
            splits.next().map(ToOwned::to_owned),
            splits.next().map(ToOwned::to_owned)
        ))
    }
}

impl Error for UserInfoParseError {
    fn description(&self) -> &str {
        "invalid user name"
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl Display for UserInfoParseError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str("invalid user name")
    }
}

#[derive(Debug, PartialEq)]
pub enum CrontabEntryParseError {
    InvalidSchedule(ScheduleParseError),
    InvalidPeriod(PeriodParseError),
    InvalidUser(UserInfoParseError),
    InvalidDelay(ParseIntError),
    InvalidEnvVarName,
    MissingPeriod,
    MissingDelay,
    MissingJobId,
    MissingEnvVarName,
    MissingEnvVarValue,
}

impl Display for CrontabEntryParseError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        use self::CrontabEntryParseError::*;
        match *self {
            InvalidSchedule(ref e) => write!(f, "invalid schedule: {}", e),
            InvalidPeriod(ref e) => write!(f, "invalid period: {}", e),
            InvalidUser(ref e) => write!(f, "invalid user: {}", e),
            InvalidDelay(ref e) => write!(f, "invalid delay: {}", e),
            _ => f.write_str(self.description()),
        }
    }
}

impl Error for CrontabEntryParseError {
    fn description(&self) -> &str {
        use self::CrontabEntryParseError::*;
        match *self {
            InvalidSchedule(_) => "invalid schedule",
            InvalidPeriod(_) => "invalid period",
            InvalidUser(_) => "invalid user",
            InvalidDelay(_) => "invalid delay",
            InvalidEnvVarName => "invalid environment variable name",
            MissingPeriod => "missing period",
            MissingDelay => "missing delay",
            MissingJobId => "missing jobid",
            MissingEnvVarName => "missing environment variable name",
            MissingEnvVarValue => "missing environment variable value",
        }
    }
    fn cause(&self) -> Option<&Error> {
        use self::CrontabEntryParseError::*;
        match *self {
            InvalidSchedule(ref e) => Some(e),
            InvalidPeriod(ref e) => Some(e),
            InvalidUser(ref e) => Some(e),
            InvalidDelay(ref e) => Some(e),
            _ => None,
        }
    }
}

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

impl FromStr for UserCrontabEntry {
    type Err = CrontabEntryParseError;

    fn from_str(s: &str) -> Result<UserCrontabEntry, CrontabEntryParseError> {
        let seps = [' ', '\t'];
        let mut splits = s.split(&seps[..]).filter(|v| *v != "");
        Ok(UserCrontabEntry {
            sched: try!(Schedule::from_iter(&mut splits)),
            cmd: splits.collect::<Vec<&str>>().connect(" ")
        })
    }
}

impl Display for SystemCrontabEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{} {} {}", self.sched, self.user, self.cmd)
    }
}

impl FromStr for SystemCrontabEntry {
    type Err = CrontabEntryParseError;

    fn from_str(s: &str) -> Result<SystemCrontabEntry, CrontabEntryParseError> {
        let seps = [' ', '\t'];
        let mut splits = s.split(&seps[..]).filter(|v| *v != "");
        Ok(SystemCrontabEntry {
            sched: try!(Schedule::from_iter(&mut splits)),
            user: try!(splits.next().ok_or(UserInfoParseError).and_then(FromStr::from_str)),
            cmd: splits.collect::<Vec<&str>>().connect(" ")
        })
    }
}

impl Display for AnacrontabEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "@{} {} {} {}", self.period, self.delay, self.jobid, self.cmd)
    }
}

impl FromStr for AnacrontabEntry {
    type Err = CrontabEntryParseError;

    fn from_str(s: &str) -> Result<AnacrontabEntry, CrontabEntryParseError> {
        let seps = [' ', '\t'];
        let mut splits = s.split(&seps[..]).filter(|v| *v != "");
        Ok(AnacrontabEntry {
            period: try!(splits.next().map(|v| v.parse().map_err(CrontabEntryParseError::InvalidPeriod)).unwrap_or(Err(CrontabEntryParseError::MissingPeriod))),
            delay: try!(splits.next().map(|v| v.parse().map_err(CrontabEntryParseError::InvalidDelay)).unwrap_or(Err(CrontabEntryParseError::MissingDelay))),
            jobid: try!(splits.next().map(ToOwned::to_owned).ok_or(CrontabEntryParseError::MissingJobId)),
            cmd: splits.collect::<Vec<&str>>().connect(" ")
        })
    }
}

impl From<ScheduleParseError> for CrontabEntryParseError {
    fn from(e: ScheduleParseError) -> CrontabEntryParseError {
        CrontabEntryParseError::InvalidSchedule(e)
    }
}

impl From<UserInfoParseError> for CrontabEntryParseError {
    fn from(e: UserInfoParseError) -> CrontabEntryParseError {
        CrontabEntryParseError::InvalidUser(e)
    }
}

impl From<ParseIntError> for CrontabEntryParseError {
    fn from(e: ParseIntError) -> CrontabEntryParseError {
        CrontabEntryParseError::InvalidDelay(e)
    }
}
<commit_msg>use join instead of deprecated connect<commit_after>use std::str::FromStr;
use std::iter::FromIterator;
use std::error::Error;
use std::convert::From;
use std::num::ParseIntError;
use std::fmt::{self, Display, Formatter};

use schedule::{Schedule, Period, Calendar, ScheduleParseError, PeriodParseError};

#[derive(Debug, PartialEq)]
pub enum CrontabEntry {
    EnvVar(EnvVarEntry),
    User(UserCrontabEntry),
    System(SystemCrontabEntry),
    Anacron(AnacrontabEntry)
}

#[derive(Debug, PartialEq)]
pub struct EnvVarEntry(pub String, pub String);

#[derive(Debug, PartialEq)]
pub struct UserCrontabEntry {
    pub sched: Schedule,
    pub cmd: String
}

#[derive(Debug, PartialEq)]
pub struct SystemCrontabEntry {
    pub sched: Schedule,
    pub user: UserInfo,
    pub cmd: String
}

#[derive(Debug, PartialEq)]
pub struct AnacrontabEntry {
    pub period: Period,
    pub delay: u32,
    pub jobid: String,
    pub cmd: String
}

impl From<UserCrontabEntry> for CrontabEntry {
    fn from(entry: UserCrontabEntry) -> CrontabEntry {
        CrontabEntry::User(entry)
    }
}

impl From<SystemCrontabEntry> for CrontabEntry {
    fn from(entry: SystemCrontabEntry) -> CrontabEntry {
        CrontabEntry::System(entry)
    }
}

impl From<AnacrontabEntry> for CrontabEntry {
    fn from(entry: AnacrontabEntry) -> CrontabEntry {
        CrontabEntry::Anacron(entry)
    }
}

impl From<EnvVarEntry> for CrontabEntry {
    fn from(entry: EnvVarEntry) -> CrontabEntry {
        CrontabEntry::EnvVar(entry)
    }
}

impl Display for CrontabEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            CrontabEntry::EnvVar(ref entry) => entry.fmt(f),
            CrontabEntry::Anacron(ref entry) => entry.fmt(f),
            CrontabEntry::User(ref entry) => entry.fmt(f),
            CrontabEntry::System(ref entry) => entry.fmt(f),
        }
    }
}

impl CrontabEntry {
    pub fn period<'a>(&'a self) -> Option<&'a Period> {
        match *self {
            CrontabEntry::Anacron(AnacrontabEntry { ref period, .. }) => Some(period),
            CrontabEntry::User(UserCrontabEntry { sched: Schedule::Period(ref period), .. }) => Some(period),
            CrontabEntry::System(SystemCrontabEntry { sched: Schedule::Period(ref period), .. }) => Some(period),
            _ => None
        }
    }

    pub fn calendar<'a>(&'a self) -> Option<&'a Calendar> {
        match *self {
            CrontabEntry::User(UserCrontabEntry { sched: Schedule::Calendar(ref cal), .. }) => Some(cal),
            CrontabEntry::System(SystemCrontabEntry { sched: Schedule::Calendar(ref cal), .. }) => Some(cal),
            _ => None
        }
    }

    pub fn command<'a>(&'a self) -> Option<&'a str> {
        match *self {
            CrontabEntry::User(UserCrontabEntry { ref cmd, .. }) => Some(&**cmd),
            CrontabEntry::System(SystemCrontabEntry { ref cmd, .. }) => Some(&**cmd),
            CrontabEntry::Anacron(AnacrontabEntry { ref cmd, .. }) => Some(&**cmd),
            _ => None
        }
    }

    pub fn user<'a>(&'a self) -> Option<&'a str> {
        match *self {
            CrontabEntry::System(SystemCrontabEntry { user: UserInfo(ref user, _, _), .. }) => Some(&**user),
            _ => None
        }
    }

    pub fn group<'a>(&'a self) -> Option<&'a str> {
        match *self {
            CrontabEntry::System(SystemCrontabEntry { user: UserInfo(_, Some(ref group), _), .. }) => Some(&**group),
            _ => None
        }
    }
}

impl Display for EnvVarEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}={}", self.0, self.1)
    }
}

impl FromStr for EnvVarEntry {
    type Err = CrontabEntryParseError;
    fn from_str(s: &str) -> Result<EnvVarEntry, CrontabEntryParseError> {
        let spaces = [' ', '\t'];
        let mut splits = s.splitn(2, '=');

        let name = match splits.next() {
            Some(n) => n.trim_right_matches(&spaces[..]),
            None => return Err(CrontabEntryParseError::MissingEnvVarName)
        };

        if name.len() == 0 {
            return Err(CrontabEntryParseError::MissingEnvVarName)
        }

        if name.chars().any(|v| v == ' ' || v == '\t') {
            return Err(CrontabEntryParseError::InvalidEnvVarName)
        }

        let mut value = match splits.next() {
            Some(v) => v.trim_left_matches(&spaces[..]),
            None => return Err(CrontabEntryParseError::MissingEnvVarValue)
        };

        if value.len() > 1 {
            if &value[..1] == "'" || &value[..1] == "\"" && &value[..1] == &value[value.len()-1..] {
                value = &value[1..value.len()-1];
            }
        }

        Ok(EnvVarEntry(name.to_owned(), value.to_owned()))
    }
}

#[derive(Debug, PartialEq)]
// user, group, class
pub struct UserInfo(pub String, pub Option<String>, pub Option<String>);

#[derive(Debug, PartialEq)]
pub struct UserInfoParseError;

impl Display for UserInfo {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(self.0.fmt(f));
        if let Some(ref group) = self.1 {
            try!(f.write_str(":"));
            try!(group.fmt(f));
        }
        if let Some(ref class) = self.2 {
            try!(f.write_str(":"));
            try!(class.fmt(f));
        }
        Ok(())
    }
}

impl FromStr for UserInfo {
    type Err = UserInfoParseError;
    fn from_str(s: &str) -> Result<UserInfo, UserInfoParseError> {
        let mut splits = s.split(':');
        Ok(UserInfo(
            try!(splits.next().ok_or(UserInfoParseError).map(ToOwned::to_owned)),
            splits.next().map(ToOwned::to_owned),
            splits.next().map(ToOwned::to_owned)
        ))
    }
}

impl Error for UserInfoParseError {
    fn description(&self) -> &str {
        "invalid user name"
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl Display for UserInfoParseError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str("invalid user name")
    }
}

#[derive(Debug, PartialEq)]
pub enum CrontabEntryParseError {
    InvalidSchedule(ScheduleParseError),
    InvalidPeriod(PeriodParseError),
    InvalidUser(UserInfoParseError),
    InvalidDelay(ParseIntError),
    InvalidEnvVarName,
    MissingPeriod,
    MissingDelay,
    MissingJobId,
    MissingEnvVarName,
    MissingEnvVarValue,
}

impl Display for CrontabEntryParseError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        use self::CrontabEntryParseError::*;
        match *self {
            InvalidSchedule(ref e) => write!(f, "invalid schedule: {}", e),
            InvalidPeriod(ref e) => write!(f, "invalid period: {}", e),
            InvalidUser(ref e) => write!(f, "invalid user: {}", e),
            InvalidDelay(ref e) => write!(f, "invalid delay: {}", e),
            _ => f.write_str(self.description()),
        }
    }
}

impl Error for CrontabEntryParseError {
    fn description(&self) -> &str {
        use self::CrontabEntryParseError::*;
        match *self {
            InvalidSchedule(_) => "invalid schedule",
            InvalidPeriod(_) => "invalid period",
            InvalidUser(_) => "invalid user",
            InvalidDelay(_) => "invalid delay",
            InvalidEnvVarName => "invalid environment variable name",
            MissingPeriod => "missing period",
            MissingDelay => "missing delay",
            MissingJobId => "missing jobid",
            MissingEnvVarName => "missing environment variable name",
            MissingEnvVarValue => "missing environment variable value",
        }
    }
    fn cause(&self) -> Option<&Error> {
        use self::CrontabEntryParseError::*;
        match *self {
            InvalidSchedule(ref e) => Some(e),
            InvalidPeriod(ref e) => Some(e),
            InvalidUser(ref e) => Some(e),
            InvalidDelay(ref e) => Some(e),
            _ => None,
        }
    }
}

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

impl FromStr for UserCrontabEntry {
    type Err = CrontabEntryParseError;

    fn from_str(s: &str) -> Result<UserCrontabEntry, CrontabEntryParseError> {
        let seps = [' ', '\t'];
        let mut splits = s.split(&seps[..]).filter(|v| *v != "");
        Ok(UserCrontabEntry {
            sched: try!(Schedule::from_iter(&mut splits)),
            cmd: splits.collect::<Vec<&str>>().join(" ")
        })
    }
}

impl Display for SystemCrontabEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{} {} {}", self.sched, self.user, self.cmd)
    }
}

impl FromStr for SystemCrontabEntry {
    type Err = CrontabEntryParseError;

    fn from_str(s: &str) -> Result<SystemCrontabEntry, CrontabEntryParseError> {
        let seps = [' ', '\t'];
        let mut splits = s.split(&seps[..]).filter(|v| *v != "");
        Ok(SystemCrontabEntry {
            sched: try!(Schedule::from_iter(&mut splits)),
            user: try!(splits.next().ok_or(UserInfoParseError).and_then(FromStr::from_str)),
            cmd: splits.collect::<Vec<&str>>().join(" ")
        })
    }
}

impl Display for AnacrontabEntry {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "@{} {} {} {}", self.period, self.delay, self.jobid, self.cmd)
    }
}

impl FromStr for AnacrontabEntry {
    type Err = CrontabEntryParseError;

    fn from_str(s: &str) -> Result<AnacrontabEntry, CrontabEntryParseError> {
        let seps = [' ', '\t'];
        let mut splits = s.split(&seps[..]).filter(|v| *v != "");
        Ok(AnacrontabEntry {
            period: try!(splits.next().map(|v| v.parse().map_err(CrontabEntryParseError::InvalidPeriod)).unwrap_or(Err(CrontabEntryParseError::MissingPeriod))),
            delay: try!(splits.next().map(|v| v.parse().map_err(CrontabEntryParseError::InvalidDelay)).unwrap_or(Err(CrontabEntryParseError::MissingDelay))),
            jobid: try!(splits.next().map(ToOwned::to_owned).ok_or(CrontabEntryParseError::MissingJobId)),
            cmd: splits.collect::<Vec<&str>>().join(" ")
        })
    }
}

impl From<ScheduleParseError> for CrontabEntryParseError {
    fn from(e: ScheduleParseError) -> CrontabEntryParseError {
        CrontabEntryParseError::InvalidSchedule(e)
    }
}

impl From<UserInfoParseError> for CrontabEntryParseError {
    fn from(e: UserInfoParseError) -> CrontabEntryParseError {
        CrontabEntryParseError::InvalidUser(e)
    }
}

impl From<ParseIntError> for CrontabEntryParseError {
    fn from(e: ParseIntError) -> CrontabEntryParseError {
        CrontabEntryParseError::InvalidDelay(e)
    }
}
<|endoftext|>


<commit_before>use graph::Mesh;
use graph::geometry::Attribute;
use graph::storage::OpaqueKey;

mod edge;
mod face;
mod vertex;

// TODO: Generalize the pairing of a ref to a mesh and a key for topology
//       within the mesh.

// This code assumes that any keys for topological structures in the mesh are
// valid (hence the `unwrap` calls), which is very important for `Deref`.
// Topological mutations using views like `FaceView` are dangerous if they do
// not consume `self`. If these views can be used to mutate that data, then
// they can also invalidate these constraints and cause panics. Any mutating
// functions should consume the view.
//
// Similarly, toplogical mutations could invalidate views used to reach other
// views. This means that it is unsafe for a mutable view to yield another
// mutable view, because the second view may cause mutations that invalidate
// the first. Circulators effectively map from a mutable view to orphan views,
// for example. While `into` and `as` functions are okay, `as...mut` functions
// MUST yield orphans (or not exist at all).

pub use self::edge::{EdgeView, OrphanEdgeView};
pub use self::face::{FaceView, OrphanFaceView};
pub use self::vertex::VertexView;

pub type EdgeRef<'a, G> = EdgeView<&'a Mesh<G>, G>;
pub type EdgeMut<'a, G> = EdgeView<&'a mut Mesh<G>, G>;
pub type OrphanEdgeMut<'a, G> = OrphanEdgeView<'a, G>;

pub type FaceRef<'a, G> = FaceView<&'a Mesh<G>, G>;
pub type FaceMut<'a, G> = FaceView<&'a mut Mesh<G>, G>;
pub type OrphanFaceMut<'a, G> = OrphanFaceView<'a, G>;

pub type VertexRef<'a, G> = VertexView<&'a Mesh<G>, G>;
pub type VertexMut<'a, G> = VertexView<&'a mut Mesh<G>, G>;

pub trait Topological {
    type Key: OpaqueKey;
    type Attribute: Attribute;
}
<commit_msg>Add docs for `topology` module.<commit_after>//! Topological views into a `Mesh`.
//!
//! This module provides topological traits and views into a `Mesh`. Views
//! allow the topology of a graph to be traversed and mutated in a consistent
//! way, and also expose the geometry of the graph.
//!
//! Views behave like references, and are exposed as `...Ref`, `...Mut`, and
//! `Orphan...Mut` types. Summarized below.
//!
//!   - `...Ref`
//!     Immutable reference to topology. Can be freely traversed, yielding
//!     arbitrary topology, but cannot mutate geometry or topology.
//!   - `...Mut`
//!     Mutable reference to topology. Traversal is limited, only yielding
//!     `Orphan...Mut` types. Allows both topology and geometry to mutate.
//!   - `Orphan...Mut`
//!     Mutable reference to geometry paired with a topological key. Cannot be
//!     traversed, but can mutate geometry and be collected.
//!
//! Note that it is not possible to get mutable views from another mutable
//! view, because a mutation may alter the topology and invalidate the
//! originating view. This means that mutable operations will always consume
//! `self` and that it is not possible to get a `...Mut` type from another
//! `...Mut` type. In general, an immutable traversal of topology can be used
//! to collect keys that are later used to query and mutate the target
//! topology.

// This code assumes that any keys for topological structures in the mesh are
// valid (hence the `unwrap` calls), which is very important for `Deref`.
// Topological mutations using views like `FaceView` are dangerous if they do
// not consume `self`. If these views can be used to mutate that data, then
// they can also invalidate these constraints and cause panics. Any mutating
// functions should consume the view.
//
// Similarly, toplogical mutations could invalidate views used to reach other
// views. This means that it is unsafe for a mutable view to yield another
// mutable view, because the second view may cause mutations that invalidate
// the first. Circulators effectively map from a mutable view to orphan views,
// for example. While `into` and `as` functions are okay, `as...mut` functions
// MUST yield orphans (or not exist at all).

use graph::Mesh;
use graph::geometry::Attribute;
use graph::storage::OpaqueKey;

mod edge;
mod face;
mod vertex;

pub use self::edge::{EdgeView, OrphanEdgeView};
pub use self::face::{FaceView, OrphanFaceView};
pub use self::vertex::VertexView;

pub type EdgeRef<'a, G> = EdgeView<&'a Mesh<G>, G>;
pub type EdgeMut<'a, G> = EdgeView<&'a mut Mesh<G>, G>;
pub type OrphanEdgeMut<'a, G> = OrphanEdgeView<'a, G>;

pub type FaceRef<'a, G> = FaceView<&'a Mesh<G>, G>;
pub type FaceMut<'a, G> = FaceView<&'a mut Mesh<G>, G>;
pub type OrphanFaceMut<'a, G> = OrphanFaceView<'a, G>;

pub type VertexRef<'a, G> = VertexView<&'a Mesh<G>, G>;
pub type VertexMut<'a, G> = VertexView<&'a mut Mesh<G>, G>;

pub trait Topological {
    type Key: OpaqueKey;
    type Attribute: Attribute;
}
<|endoftext|>


<commit_before>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use runner;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io,
    pub name_stack: Vec<String>,
    pub failures: Vec<String>,
}

impl<'a, T: io::Write> Simple<'a, T> {
    pub fn new(buf: &mut T) -> Simple<T> {
        Simple { buf: buf, name_stack: vec!(), failures: vec!() }
    }

    fn write_summary(&mut self, result: runner::RunnerResult) -> Result<(), io::Error> {
        let (res, report) = match result {
            Ok(report) => ("ok", report),
            Err(report) => ("FAILED", report),
        };

        writeln!(self.buf,
                 "\n\ntest result: {}. {} examples; {} passed; {} failed;",
                 res,
                 report.total_tests,
                 report.success_count,
                 report.error_count)
    }
}

impl<'a, T: io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: &Event) {
        // FIXME: do something with the io::Error ?
        let _ = match *event {
            Event::StartRunner => writeln!(self.buf, "Running tests:\n"),
            Event::StartTest(ref name) => { self.name_stack.push(name.clone()); Ok(()) },
            Event::EndTest(result) => {
                if !self.name_stack.is_empty() {
                    let failure_name = self.name_stack.join(" | ");
                    self.failures.push(failure_name);
                    self.name_stack.pop();
                }
                let chr = if result.is_ok() {
                    "."
                } else {
                    "F"
                };
                write!(self.buf, "{}", chr)
            }
            Event::FinishedRunner(result) => self.write_summary(result),
            Event::StartDescribe(ref name) => { self.name_stack.push(name.clone()); Ok(()) },
            Event::EndDescribe => { self.name_stack.pop(); Ok(()) },
            //_ => Ok(()),
        };
    }
}
impl<'a, T: io::Write> Formatter for Simple<'a, T> {}

#[cfg(test)]
mod tests {
    pub use super::*;
    pub use formatter::formatter::Formatter;
    pub use events::{Event, EventHandler};
    pub use std::io;
    pub use std::str;

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec![1u8]);
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _: &Formatter = &Simple::new(&mut vec![1u8]) as &Formatter;
    }

    mod event_start_runner {
        pub use super::*;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::StartRunner);
            }

            assert_eq!("Running tests:\n\n", str::from_utf8(&v).unwrap());
        }
    }

    mod event_finished_runner {
        pub use super::*;
        use runner::TestReport;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        macro_rules! test_and_compare_output {
            ($(
                $test_name:ident : (success: $succ:expr, errors: $err:expr) => $msg:expr
            ),+) => {

                $(
                    #[test]
                    fn $test_name() {
                        let mut v = vec!();
                        {
                            let mut s = Simple::new(&mut v);
                            s.trigger(&Event::FinishedRunner(make_report($succ, $err)))
                        }

                        assert_eq!($msg, str::from_utf8(&v).unwrap())
                    }
                )+
            }
        }

        test_and_compare_output! {
            no_test_is_ok: (success: 0, errors: 0) =>
                "\n\ntest result: ok. 0 examples; 0 passed; 0 failed;\n",
            one_test: (success: 1, errors: 0) =>
                "\n\ntest result: ok. 1 examples; 1 passed; 0 failed;\n",
            multiple_ok: (success: 42, errors: 0) =>
                "\n\ntest result: ok. 42 examples; 42 passed; 0 failed;\n",
            one_error: (success: 0, errors: 1) =>
              "\n\ntest result: FAILED. 1 examples; 0 passed; 1 failed;\n",
            multiple_errors: (success: 0, errors: 37) =>
              "\n\ntest result: FAILED. 37 examples; 0 passed; 37 failed;\n",
            one_of_each: (success: 1, errors: 1) =>
              "\n\ntest result: FAILED. 2 examples; 1 passed; 1 failed;\n",
            multiple_of_each: (success: 12, errors: 21) =>
              "\n\ntest result: FAILED. 33 examples; 12 passed; 21 failed;\n"
        }
    }

    mod event_end_test {
        pub use super::*;

        #[test]
        fn it_displays_a_dot_when_success() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Ok(())));
            }

            assert_eq!(".", str::from_utf8(&v).unwrap());
        }

        #[test]
        #[allow(non_snake_case)]
        fn it_displays_a_F_when_error() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Err(())));
            }

            assert_eq!("F", str::from_utf8(&v).unwrap());
        }
    }

    mod event_start_end_describe {
        pub use super::*;

        #[test]
        fn start_describe_event_push_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            assert_eq!(vec!(String::from("Hey !")), s.name_stack);

            s.trigger(&Event::StartDescribe(String::from("Ho !")));
            assert_eq!(vec!(String::from("Hey !"), String::from("Ho !")), s.name_stack)
        }

        #[test]
        fn end_describe_event_pop_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            s.trigger(&Event::StartDescribe(String::from("Ho !")));

            s.trigger(&Event::EndDescribe);
            assert_eq!(vec!(String::from("Hey !")), s.name_stack);

            s.trigger(&Event::EndDescribe);
            assert_eq!(0, s.name_stack.len());
        }
    }

    mod failures_pretty_printing {
        use super::*;

        #[test]
        fn it_register_failures() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(1, s.failures.len());
        }

        #[test]
        fn it_keep_track_of_the_failure_name() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola".into()), s.failures.get(0));
        }

        #[test]
        fn it_has_a_nice_diplay_for_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | holé".into()), s.failures.get(0));

            s.trigger(&Event::StartDescribe("ohééé".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | ohééé | holé".into()), s.failures.get(1));
        }

        #[test]
        fn it_works_with_multiple_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));

            s.trigger(&Event::EndDescribe);
            s.trigger(&Event::StartDescribe("ok".into()));
            s.trigger(&Event::StartTest("cacao".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"ok | cacao".into()), s.failures.get(1));
        }

        // test the correct formating of one failure
        //#[test]
        //fn format_all_failures() {
        //    let mut buf = vec!();
        //    {
        //        let mut s = Simple::new(&mut buf);
        //        s.trigger(&Event::StartDescribe("hola".into()));
        //        s.trigger(&Event::StartTest("holé".into()));
        //        s.trigger(&Event::EndTest(Err(())));
        //    }

        //    let expect = ""
        //}
    }
}
<commit_msg> cargo fmt<commit_after>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use runner;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io,
    pub name_stack: Vec<String>,
    pub failures: Vec<String>,
}

impl<'a, T: io::Write> Simple<'a, T> {
    pub fn new(buf: &mut T) -> Simple<T> {
        Simple {
            buf: buf,
            name_stack: vec![],
            failures: vec![],
        }
    }

    fn write_summary(&mut self, result: runner::RunnerResult) -> Result<(), io::Error> {
        let (res, report) = match result {
            Ok(report) => ("ok", report),
            Err(report) => ("FAILED", report),
        };

        writeln!(self.buf,
                 "\n\ntest result: {}. {} examples; {} passed; {} failed;",
                 res,
                 report.total_tests,
                 report.success_count,
                 report.error_count)
    }
}

impl<'a, T: io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: &Event) {
        // FIXME: do something with the io::Error ?
        let _ = match *event {
            Event::StartRunner => writeln!(self.buf, "Running tests:\n"),
            Event::StartTest(ref name) => {
                self.name_stack.push(name.clone());
                Ok(())
            }
            Event::EndTest(result) => {
                if !self.name_stack.is_empty() {
                    let failure_name = self.name_stack.join(" | ");
                    self.failures.push(failure_name);
                    self.name_stack.pop();
                }
                let chr = if result.is_ok() {
                    "."
                } else {
                    "F"
                };
                write!(self.buf, "{}", chr)
            }
            Event::FinishedRunner(result) => self.write_summary(result),
            Event::StartDescribe(ref name) => {
                self.name_stack.push(name.clone());
                Ok(())
            }
            Event::EndDescribe => {
                self.name_stack.pop();
                Ok(())
            }
            // _ => Ok(()),
        };
    }
}
impl<'a, T: io::Write> Formatter for Simple<'a, T> {}

#[cfg(test)]
mod tests {
    pub use super::*;
    pub use formatter::formatter::Formatter;
    pub use events::{Event, EventHandler};
    pub use std::io;
    pub use std::str;

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec![1u8]);
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _: &Formatter = &Simple::new(&mut vec![1u8]) as &Formatter;
    }

    mod event_start_runner {
        pub use super::*;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::StartRunner);
            }

            assert_eq!("Running tests:\n\n", str::from_utf8(&v).unwrap());
        }
    }

    mod event_finished_runner {
        pub use super::*;
        use runner::TestReport;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        macro_rules! test_and_compare_output {
            ($(
                $test_name:ident : (success: $succ:expr, errors: $err:expr) => $msg:expr
            ),+) => {

                $(
                    #[test]
                    fn $test_name() {
                        let mut v = vec!();
                        {
                            let mut s = Simple::new(&mut v);
                            s.trigger(&Event::FinishedRunner(make_report($succ, $err)))
                        }

                        assert_eq!($msg, str::from_utf8(&v).unwrap())
                    }
                )+
            }
        }

        test_and_compare_output! {
            no_test_is_ok: (success: 0, errors: 0) =>
                "\n\ntest result: ok. 0 examples; 0 passed; 0 failed;\n",
            one_test: (success: 1, errors: 0) =>
                "\n\ntest result: ok. 1 examples; 1 passed; 0 failed;\n",
            multiple_ok: (success: 42, errors: 0) =>
                "\n\ntest result: ok. 42 examples; 42 passed; 0 failed;\n",
            one_error: (success: 0, errors: 1) =>
              "\n\ntest result: FAILED. 1 examples; 0 passed; 1 failed;\n",
            multiple_errors: (success: 0, errors: 37) =>
              "\n\ntest result: FAILED. 37 examples; 0 passed; 37 failed;\n",
            one_of_each: (success: 1, errors: 1) =>
              "\n\ntest result: FAILED. 2 examples; 1 passed; 1 failed;\n",
            multiple_of_each: (success: 12, errors: 21) =>
              "\n\ntest result: FAILED. 33 examples; 12 passed; 21 failed;\n"
        }
    }

    mod event_end_test {
        pub use super::*;

        #[test]
        fn it_displays_a_dot_when_success() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Ok(())));
            }

            assert_eq!(".", str::from_utf8(&v).unwrap());
        }

        #[test]
        #[allow(non_snake_case)]
        fn it_displays_a_F_when_error() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Err(())));
            }

            assert_eq!("F", str::from_utf8(&v).unwrap());
        }
    }

    mod event_start_end_describe {
        pub use super::*;

        #[test]
        fn start_describe_event_push_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            assert_eq!(vec![String::from("Hey !")], s.name_stack);

            s.trigger(&Event::StartDescribe(String::from("Ho !")));
            assert_eq!(vec![String::from("Hey !"), String::from("Ho !")],
                       s.name_stack)
        }

        #[test]
        fn end_describe_event_pop_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            s.trigger(&Event::StartDescribe(String::from("Ho !")));

            s.trigger(&Event::EndDescribe);
            assert_eq!(vec![String::from("Hey !")], s.name_stack);

            s.trigger(&Event::EndDescribe);
            assert_eq!(0, s.name_stack.len());
        }
    }

    mod failures_pretty_printing {
        use super::*;

        #[test]
        fn it_register_failures() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(1, s.failures.len());
        }

        #[test]
        fn it_keep_track_of_the_failure_name() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola".into()), s.failures.get(0));
        }

        #[test]
        fn it_has_a_nice_diplay_for_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | holé".into()), s.failures.get(0));

            s.trigger(&Event::StartDescribe("ohééé".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | ohééé | holé".into()), s.failures.get(1));
        }

        #[test]
        fn it_works_with_multiple_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));

            s.trigger(&Event::EndDescribe);
            s.trigger(&Event::StartDescribe("ok".into()));
            s.trigger(&Event::StartTest("cacao".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"ok | cacao".into()), s.failures.get(1));
        }

        // test the correct formating of one failure
        // #[test]
        // fn format_all_failures() {
        //    let mut buf = vec!();
        //    {
        //        let mut s = Simple::new(&mut buf);
        //        s.trigger(&Event::StartDescribe("hola".into()));
        //        s.trigger(&Event::StartTest("holé".into()));
        //        s.trigger(&Event::EndTest(Err(())));
        //    }

        //    let expect = ""
        // }
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use temperature::{self, Simulator};

use profile::Profile;
use schedule::Decision;
use {Config, Error, Job, Result};

pub struct Platform {
    elements: Vec<Element>,
    simulator: Simulator,
    power: Profile,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Element {
    pub id: usize,
    pub kind: Kind,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Kind {
    Core,
    L3,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Capacity {
    Single,
    Infinite,
}

impl Platform {
    pub fn new(config: &Config) -> Result<Platform> {
        let (elements, circuit) = try!(construct_threed_ice_cirucit(config));

        info!(target: "Platform", "Initializing the temperature simulator...");
        let config = try!(extract_temperature_config(config));
        let simulator = ok!(Simulator::new(&circuit, &config));

        let power = Profile::new(elements.len(), config.time_step);

        Ok(Platform { elements: elements, simulator: simulator, power: power })
    }

    pub fn push(&mut self, job: &Job, decision: &Decision) -> Result<()> {
        let pattern = &job.pattern;
        let (from, onto) = (&pattern.elements, &self.elements);
        for &(i, j) in &decision.mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.power.push(onto.id, decision.start, pattern.time_step, &from.dynamic_power,
                            from.leakage_power);
        }
        Ok(())
    }

    pub fn next(&mut self, time: f64) -> Option<(Profile, Profile)> {
        let power = self.power.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    getters! {
        ref elements: [Element],
    }
}

impl Element {
    #[inline(always)]
    pub fn capacity(&self) -> Capacity {
        if self.kind == Kind::Core {
            Capacity::Single
        } else {
            Capacity::Infinite
        }
    }
}

impl FromStr for Kind {
    type Err = Error;

    fn from_str(id: &str) -> Result<Self> {
        let lower = id.to_lowercase();
        if lower.starts_with("core") {
            return Ok(Kind::Core);
        } else if lower.starts_with("l3") {
            return Ok(Kind::L3);
        }
        raise!("found an unknown id {:?}", id);
    }
}

fn construct_threed_ice_cirucit(config: &Config) -> Result<(Vec<Element>, temperature::Circuit)> {
    use temperature::circuit::ThreeDICE;
    use threed_ice::{StackElement, System};

    let path = path!(config, "a stack description");

    info!(target: "Platform", "Reading {:?}...", &path);
    let system = ok!(System::new(&path));

    let mut elements = vec![];
    for element in system.stack.elements.iter().rev() {
        let die = match element {
            &StackElement::Die(ref die) => die,
            _ => continue,
        };
        for element in die.floorplan.elements.iter() {
            let id = elements.len();
            let kind = try!(Kind::from_str(&element.id));
            elements.push(Element { id: id, kind: kind });
        }
    }
    info!(target: "Platform", "Found {} processing elements.", elements.len());

    info!(target: "Platform", "Constructing a thermal circuit...");
    let circuit = ok!(ThreeDICE::from(&system));
    info!(target: "Platform", "Obtained {} thermal nodes.", circuit.capacitance.len());

    Ok((elements, circuit))
}

fn extract_temperature_config(config: &Config) -> Result<temperature::Config> {
    Ok(temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    })
}

#[cfg(test)]
mod tests {
    use configuration::format::TOML;
    use super::{Kind, Element, Platform};

    #[test]
    fn new() {
        let config = TOML::open("tests/fixtures/streamer.toml").unwrap()
                                                               .branch("platform")
                                                               .unwrap();
        let platform = Platform::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, kind: Kind::Core },
            Element { id: 1, kind: Kind::Core },
            Element { id: 2, kind: Kind::Core },
            Element { id: 3, kind: Kind::Core },
            Element { id: 4, kind: Kind::L3 },
        ]);
    }
}
<commit_msg>Platform: rearrange info logging<commit_after>use std::str::FromStr;
use temperature::{self, Simulator};

use profile::Profile;
use schedule::Decision;
use {Config, Error, Job, Result};

pub struct Platform {
    elements: Vec<Element>,
    simulator: Simulator,
    power: Profile,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Element {
    pub id: usize,
    pub kind: Kind,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Kind {
    Core,
    L3,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Capacity {
    Single,
    Infinite,
}

impl Platform {
    pub fn new(config: &Config) -> Result<Platform> {
        let (elements, circuit) = try!(construct_threed_ice_cirucit(config));
        info!(target: "Platform", "Found {} processing elements and obtained {} thermal nodes.",
              elements.len(), circuit.capacitance.len());

        info!(target: "Platform", "Initializing the temperature simulator...");
        let config = try!(extract_temperature_config(config));
        let simulator = ok!(Simulator::new(&circuit, &config));

        let power = Profile::new(elements.len(), config.time_step);

        Ok(Platform { elements: elements, simulator: simulator, power: power })
    }

    pub fn push(&mut self, job: &Job, decision: &Decision) -> Result<()> {
        let pattern = &job.pattern;
        let (from, onto) = (&pattern.elements, &self.elements);
        for &(i, j) in &decision.mapping {
            let (from, onto) = (&from[i], &onto[j]);
            self.power.push(onto.id, decision.start, pattern.time_step, &from.dynamic_power,
                            from.leakage_power);
        }
        Ok(())
    }

    pub fn next(&mut self, time: f64) -> Option<(Profile, Profile)> {
        let power = self.power.pull(time);
        let mut temperature = power.clone_zero();
        self.simulator.next(&power, &mut temperature);
        Some((power, temperature))
    }

    getters! {
        ref elements: [Element],
    }
}

impl Element {
    #[inline(always)]
    pub fn capacity(&self) -> Capacity {
        if self.kind == Kind::Core {
            Capacity::Single
        } else {
            Capacity::Infinite
        }
    }
}

impl FromStr for Kind {
    type Err = Error;

    fn from_str(id: &str) -> Result<Self> {
        let lower = id.to_lowercase();
        if lower.starts_with("core") {
            return Ok(Kind::Core);
        } else if lower.starts_with("l3") {
            return Ok(Kind::L3);
        }
        raise!("found an unknown id {:?}", id);
    }
}

fn construct_threed_ice_cirucit(config: &Config) -> Result<(Vec<Element>, temperature::Circuit)> {
    use temperature::circuit::ThreeDICE;
    use threed_ice::{StackElement, System};

    let path = path!(config, "a stack description");

    info!(target: "Platform", "Reading {:?}...", &path);
    let system = ok!(System::new(&path));

    let mut elements = vec![];
    for element in system.stack.elements.iter().rev() {
        let die = match element {
            &StackElement::Die(ref die) => die,
            _ => continue,
        };
        for element in die.floorplan.elements.iter() {
            let id = elements.len();
            let kind = try!(Kind::from_str(&element.id));
            elements.push(Element { id: id, kind: kind });
        }
    }

    info!(target: "Platform", "Constructing a thermal circuit...");
    let circuit = ok!(ThreeDICE::from(&system));

    Ok((elements, circuit))
}

fn extract_temperature_config(config: &Config) -> Result<temperature::Config> {
    Ok(temperature::Config {
        ambience: *some!(config.get::<f64>("ambience"), "an ambient temperature is required"),
        time_step: *some!(config.get::<f64>("time_step"), "a time step is required"),
    })
}

#[cfg(test)]
mod tests {
    use configuration::format::TOML;
    use super::{Kind, Element, Platform};

    #[test]
    fn new() {
        let config = TOML::open("tests/fixtures/streamer.toml").unwrap()
                                                               .branch("platform")
                                                               .unwrap();
        let platform = Platform::new(&config).unwrap();
        assert_eq!(platform.elements, &[
            Element { id: 0, kind: Kind::Core },
            Element { id: 1, kind: Kind::Core },
            Element { id: 2, kind: Kind::Core },
            Element { id: 3, kind: Kind::Core },
            Element { id: 4, kind: Kind::L3 },
        ]);
    }
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![feature(box_patterns, alloc)]

// warnings
#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(std_misc)]

extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::MessageStatic;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

// used by test
pub mod hex;

mod misc;
mod zigzag;
mod maybe_owned_slice;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

// so `use protobuf::*` could work in descriptor mod
mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use text_format;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<commit_msg>Enable unstable str_char feature<commit_after>#![crate_type = "lib"]
#![feature(box_patterns, alloc)]

// warnings
#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(std_misc)]
#![feature(str_char)]

extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::MessageStatic;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

// used by test
pub mod hex;

mod misc;
mod zigzag;
mod maybe_owned_slice;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

// so `use protobuf::*` could work in descriptor mod
mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use text_format;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<|endoftext|>