<commit_before>
//! Framebuffers are used to draw to off-screen render targets

use gl;
use std;
use std::io;
use gl::types::*;
use texture::TextureFormat;

/// Utility to specify the format of a framebuffer before building it.
pub struct FramebufferProperties {
    /// Size in pixels
    pub width: u32,
    /// Size in pixels
    pub height: u32,
    /// The format in which color data is stored internally
    pub internal_format: TextureFormat,
    /// If `true` a depthbuffer will be constructed for framebuffers
    pub depth_buffer: bool,
}

impl FramebufferProperties {
    pub fn new(width: u32, height: u32) -> FramebufferProperties {
        FramebufferProperties {
            width: width,
            height: height,
            internal_format: TextureFormat::RGB_8,
            depth_buffer: false,
        }
    }

    /// Creates a new framebuffer with these properties
    pub fn build(&self) -> io::Result<Framebuffer> {
        Framebuffer::new(&self)
    }
}

/// A OpenGL framebuffer that is ready to be used. Framebuffers are constructed from
/// [`FramebufferProperties`](struct.FramebufferProperties.html).
pub struct Framebuffer {
    framebuffer: GLuint,
    texture: GLuint,
    depth_buffer: Option<GLuint>,
    pub width: u32,
    pub height: u32
}

impl Framebuffer {
    fn new(properties: &FramebufferProperties) -> io::Result<Framebuffer> {
        let mut framebuffer: GLuint = 0;
        let mut texture: GLuint = 0;
        let mut depth_buffer: Option<GLuint> = None;

        let mut error: Option<String> = None;

        unsafe {
            gl::GenFramebuffers(1, &mut framebuffer);
            gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);

            gl::GenTextures(1, &mut texture);
            gl::BindTexture(gl::TEXTURE_2D, texture);
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0, // Level
                properties.internal_format as GLint,
                properties.width as GLint, properties.height as GLint, 0, //Size and border
                gl::RGBA, gl::UNSIGNED_BYTE, std::ptr::null() // Data for texture
            );

            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);

            gl::FramebufferTexture(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, texture, 0);
            gl::DrawBuffers(1, &gl::COLOR_ATTACHMENT0);

            if properties.depth_buffer {
                let mut depth_buffer_handle = 0;
                gl::GenRenderbuffers(1, &mut depth_buffer_handle);
                gl::BindRenderbuffer(gl::RENDERBUFFER, depth_buffer_handle);
                gl::RenderbufferStorage(gl::RENDERBUFFER, gl::DEPTH_COMPONENT16,
                                        properties.width as GLint, properties.height as GLint);
                gl::FramebufferRenderbuffer(gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, gl::RENDERBUFFER, depth_buffer_handle);
                depth_buffer = Some(depth_buffer_handle);
            }

            let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
            if status != gl::FRAMEBUFFER_COMPLETE {
                gl::DeleteFramebuffers(1, &framebuffer);
                gl::DeleteTextures(1, &texture);
                if let Some(depth_buffer) = depth_buffer {
                    gl::DeleteRenderbuffers(1, &depth_buffer);
                }
                error = Some(format!("Framebuffer error: {}", get_status_message(status)));
            }

            gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
        }

        if let Some(error) = error {
            return Err(io::Error::new(io::ErrorKind::Other, error));
        } else {
            return Ok(
                Framebuffer {
                    framebuffer: framebuffer,
                    texture: texture,
                    depth_buffer: depth_buffer,
                    width: properties.width,
                    height: properties.height,
                }
            );
        }
    }

    /// Binds this framebuffer. Subsequent draw operations will modify this framebuffer
    /// rather than the backbuffer. Note that you probably want to modify the viewport
    /// to fit this framebuffers size.
    pub fn bind(&self) {
        unsafe {
            gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer);
        }
    }

    /// Binds framebuffer 0, resulting in draw operations drawing to the backbuffer.
    pub fn unbind(&self) {
        unsafe {
            gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
        }
    }

    /// Moves the contents of this framebuffer to the given framebuffer, resolving multisampling
    /// if present. Note that this also unbinds this framebuffer
    pub fn blit_to_framebuffer(&self, other: &Framebuffer) {
        self.blit_indexed(other.framebuffer, other.width, other.height);
    }

    /// Moves the contents of this framebuffer to the backbuffer, resolving multisampling
    /// if present. Note that this also unbinds this framebuffer. This will only partially
    /// cover the backbuffer if this framebuffer is smaller than the backbuffer. To upscale
    /// a framebuffer while blitting, use [`blit_with_size`](struct.Framebuffer.html#method.blit_with_size).
    pub fn blit(&self) {
        self.blit_indexed(0, self.width, self.height);
    }

    /// Moves the contents of this framebuffer to the backbuffer, resolving multisampling
    /// if present. Note that this also unbinds this framebuffer. This allows setting
    /// the size to which this framebuffer should be scaled while blitting. This should
    /// be used if the framebuffer is larger or smaller than the backbuffer.
    pub fn blit_with_size(&self, width: u32, height: u32) {
        self.blit_indexed(0, width, height);
    }

    fn blit_indexed(&self, target: GLuint, dst_width: u32, dst_height: u32) {
        unsafe {
            gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, target);
            gl::BindFramebuffer(gl::READ_FRAMEBUFFER, self.framebuffer);
            gl::BlitFramebuffer(
                0, 0, self.width as i32, self.height as i32,
                0, 0, dst_width as i32, dst_height as i32,
                gl::COLOR_BUFFER_BIT,
                gl::NEAREST
            );
        }
        self.unbind();
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.framebuffer);
            gl::DeleteTextures(1, &self.texture);
            if let Some(depth_buffer) = self.depth_buffer {
                gl::DeleteRenderbuffers(1, &depth_buffer);
            }
        }
    }
}

fn get_status_message(message: GLenum) -> String {
    String::from(match message {
        gl::FRAMEBUFFER_UNDEFINED                     => "GL_FRAMEBUFFER_UNDEFINED",
        gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT         => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
        gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
        gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        => "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
        gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER        => "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
        gl::FRAMEBUFFER_UNSUPPORTED                   => "GL_FRAMEBUFFER_UNSUPPORTED",
        gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE        => "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE",
        gl::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS      => "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS",
        _ => return format!("Unkown error ({})", message)
    })
}

<commit_msg>Multisampling support<commit_after>
//! Framebuffers are used to draw to off-screen render targets

use gl;
use std;
use std::io;
use gl::types::*;
use texture::TextureFormat;

/// Utility to specify the format of a framebuffer before building it.
pub struct FramebufferProperties {
    /// Size in pixels
    pub width: u32,
    /// Size in pixels
    pub height: u32,
    /// The amount of multisampling to apply
    pub multisample: Option<usize>,
    /// The format in which color data is stored internally
    pub internal_format: TextureFormat,
    /// If `true` a depthbuffer will be constructed for framebuffers
    pub depth_buffer: bool,
}

impl FramebufferProperties {
    pub fn new(width: u32, height: u32) -> FramebufferProperties {
        FramebufferProperties {
            width: width,
            height: height,
            multisample: None,
            internal_format: TextureFormat::RGB_8,
            depth_buffer: false,
        }
    }

    /// Creates a new framebuffer with these properties
    pub fn build(&self) -> io::Result<Framebuffer> {
        Framebuffer::new(&self)
    }
}

/// A OpenGL framebuffer that is ready to be used. Framebuffers are constructed from
/// [`FramebufferProperties`](struct.FramebufferProperties.html).
pub struct Framebuffer {
    framebuffer: GLuint,
    texture: GLuint,
    depth_buffer: Option<GLuint>,
    pub width: u32,
    pub height: u32
}

impl Framebuffer {
    fn new(properties: &FramebufferProperties) -> io::Result<Framebuffer> {
        let mut framebuffer: GLuint = 0;
        let mut texture: GLuint = 0;
        let mut depth_buffer: Option<GLuint> = None;

        let mut error: Option<String> = None;

        unsafe {
            gl::GenFramebuffers(1, &mut framebuffer);
            gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);

            let texture_target = if properties.multisample.is_none() { gl::TEXTURE_2D } else { gl::TEXTURE_2D_MULTISAMPLE };

            gl::GenTextures(1, &mut texture);
            gl::BindTexture(texture_target, texture);
            ::util::graphics::print_errors();
            if let Some(level) = properties.multisample {
                gl::TexImage2DMultisample(texture_target,
                                          level as GLsizei,
                                          properties.internal_format as GLuint,
                                          properties.width as GLint, properties.height as GLint, //Size
                                          true as GLboolean); // Fixed sample locations
            } else {
                gl::TexImage2D(texture_target,
                               0, // Level
                               properties.internal_format as GLint,
                               properties.width as GLint, properties.height as GLint, 0, //Size and border
                               gl::RGBA, gl::UNSIGNED_BYTE, std::ptr::null()); // Data for texture
                gl::TexParameteri(texture_target, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
                gl::TexParameteri(texture_target, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
                gl::TexParameteri(texture_target, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
                gl::TexParameteri(texture_target, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
                gl::TexParameteri(texture_target, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
            }

            gl::FramebufferTexture(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, texture, 0);
            gl::DrawBuffers(1, &gl::COLOR_ATTACHMENT0);

            if properties.depth_buffer {
                let mut depth_buffer_handle = 0;
                gl::GenRenderbuffers(1, &mut depth_buffer_handle);
                gl::BindRenderbuffer(gl::RENDERBUFFER, depth_buffer_handle);
                if let Some(level) = properties.multisample {
                    gl::RenderbufferStorageMultisample(gl::RENDERBUFFER, level as GLsizei, gl::DEPTH_COMPONENT16,
                                                       properties.width as GLint, properties.height as GLint);
                } else {
                    gl::RenderbufferStorage(gl::RENDERBUFFER, gl::DEPTH_COMPONENT16,
                                            properties.width as GLint, properties.height as GLint);
                }
                gl::FramebufferRenderbuffer(gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, gl::RENDERBUFFER, depth_buffer_handle);
                depth_buffer = Some(depth_buffer_handle);
            }

            let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
            if status != gl::FRAMEBUFFER_COMPLETE {
                gl::DeleteFramebuffers(1, &framebuffer);
                gl::DeleteTextures(1, &texture);
                if let Some(depth_buffer) = depth_buffer {
                    gl::DeleteRenderbuffers(1, &depth_buffer);
                }
                error = Some(format!("Framebuffer error: {}", get_status_message(status)));
            }

            gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
        }

        if let Some(error) = error {
            return Err(io::Error::new(io::ErrorKind::Other, error));
        } else {
            return Ok(
                Framebuffer {
                    framebuffer: framebuffer,
                    texture: texture,
                    depth_buffer: depth_buffer,
                    width: properties.width,
                    height: properties.height,
                }
            );
        }
    }

    /// Binds this framebuffer. Subsequent draw operations will modify this framebuffer
    /// rather than the backbuffer. Note that you probably want to modify the viewport
    /// to fit this framebuffers size.
    pub fn bind(&self) {
        unsafe {
            gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer);
        }
    }

    /// Binds framebuffer 0, resulting in draw operations drawing to the backbuffer.
    pub fn unbind(&self) {
        unsafe {
            gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
        }
    }

    /// Moves the contents of this framebuffer to the given framebuffer, resolving multisampling
    /// if present. Note that this also unbinds this framebuffer
    pub fn blit_to_framebuffer(&self, other: &Framebuffer) {
        self.blit_indexed(other.framebuffer, other.width, other.height);
    }

    /// Moves the contents of this framebuffer to the backbuffer, resolving multisampling
    /// if present. Note that this also unbinds this framebuffer. This will only partially
    /// cover the backbuffer if this framebuffer is smaller than the backbuffer. To upscale
    /// a framebuffer while blitting, use [`blit_with_size`](struct.Framebuffer.html#method.blit_with_size).
    pub fn blit(&self) {
        self.blit_indexed(0, self.width, self.height);
    }

    /// Moves the contents of this framebuffer to the backbuffer, resolving multisampling
    /// if present. Note that this also unbinds this framebuffer. This allows setting
    /// the size to which this framebuffer should be scaled while blitting. This should
    /// be used if the framebuffer is larger or smaller than the backbuffer.
    pub fn blit_with_size(&self, width: u32, height: u32) {
        self.blit_indexed(0, width, height);
    }

    fn blit_indexed(&self, target: GLuint, dst_width: u32, dst_height: u32) {
        unsafe {
            gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, target);
            gl::BindFramebuffer(gl::READ_FRAMEBUFFER, self.framebuffer);
            gl::BlitFramebuffer(
                0, 0, self.width as i32, self.height as i32,
                0, 0, dst_width as i32, dst_height as i32,
                gl::COLOR_BUFFER_BIT,
                gl::NEAREST
            );
        }
        self.unbind();
    }
}

impl Drop for Framebuffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteFramebuffers(1, &self.framebuffer);
            gl::DeleteTextures(1, &self.texture);
            if let Some(depth_buffer) = self.depth_buffer {
                gl::DeleteRenderbuffers(1, &depth_buffer);
            }
        }
    }
}

fn get_status_message(message: GLenum) -> String {
    String::from(match message {
        gl::FRAMEBUFFER_UNDEFINED                     => "GL_FRAMEBUFFER_UNDEFINED",
        gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT         => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
        gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
        gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        => "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
        gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER        => "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
        gl::FRAMEBUFFER_UNSUPPORTED                   => "GL_FRAMEBUFFER_UNSUPPORTED",
        gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE        => "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE",
        gl::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS      => "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS",
        _ => return format!("Unkown error ({})", message)
    })
}

<|endoftext|>


<commit_before>use crate::AsArray1D;
use plotpy::{Plot, Shapes};
use std::collections::HashMap;

/// Holds the id and coordinates of an item
#[derive(Clone)]
struct Item {
    id: usize,   // identification number
    x: [f64; 3], // coordinates
}

/// Holds items
#[derive(Clone)]
struct Container {
    items: Vec<Item>,
}

/// Implements a grid for fast searching entries by coordinates
///
/// # Reference
///
/// * Durand, Farias, and Pedroso (2015) Computing intersections between
///   non-compatible curves and finite elements, Computational Mechanics;
///   DOI=10.1007/s00466-015-1181-y
pub struct GridSearch {
    // constants
    ndim: usize,      // space dimension
    ndiv: [usize; 3], // number of divisions along each direction
    xmin: [f64; 3],   // min values
    xmax: [f64; 3],   // max values
    xdelta: [f64; 3], // difference between max and min
    size: [f64; 3],   // size of each cell
    cf: [usize; 3],   // coefficients [1, ndiv[0], ndiv[0]*ndiv[1]] (Eq. 8)

    // auxiliary variable
    ratio: [usize; 3], // ratio = trunc(δx[i]/Δx[i]) (Eq. 8)

    // holds non-empty cells. maps cell.id to container
    cells: HashMap<usize, Container>,
}

impl GridSearch {
    /// Creates a new GridSearch
    ///
    /// # Input
    ///
    /// * `xmin, xmax` -- min and max coordinates (len = 2 or 3 == ndim)
    /// * `ndiv` -- number of divisions along each dimension (len = 2 or 3 == ndim)
    pub fn new(xmin: &[f64], xmax: &[f64], ndiv: &[usize]) -> Result<Self, &'static str> {
        // check input
        let ndim = ndiv.len();
        if ndim < 2 || ndim > 3 {
            return Err("ndim must be 2 or 3");
        }
        if xmin.len() != ndim {
            return Err("size of xmin must equal ndim");
        }
        if xmax.len() != ndim {
            return Err("size of xmax must equal ndim");
        }

        // allocate gs
        let mut grid = GridSearch {
            ndim,
            ndiv: [0; 3],
            xmin: [0.0; 3],
            xmax: [0.0; 3],
            xdelta: [0.0; 3],
            size: [0.0; 3],
            ratio: [0; 3],
            cf: [0; 3],
            cells: HashMap::new(),
        };

        // check and compute sizes
        for i in 0..ndim {
            grid.ndiv[i] = ndiv[i];
            if ndiv[i] < 1 {
                return Err("ndiv must be at least 1");
            }
            grid.xmin[i] = xmin[i];
            grid.xmax[i] = xmax[i];
            grid.xdelta[i] = xmax[i] - xmin[i];
            if grid.xdelta[i] <= 0.0 {
                return Err("xmax must be greater than xmin");
            }
            grid.size[i] = grid.xdelta[i] / (ndiv[i] as f64);
        }

        // coefficient
        grid.cf[0] = 1;
        grid.cf[1] = grid.ndiv[0];
        grid.cf[2] = grid.ndiv[0] * grid.ndiv[1];

        // done
        Ok(grid)
    }

    /// Inserts a new item to some container in the grid
    ///
    /// # Input
    ///
    /// * `id` -- identification number for the item
    /// * `x` -- coordinates of the item (an 1D array with len = ndim)
    pub fn insert<'a, T, U>(&mut self, id: usize, x: &'a T) -> Result<(), &'static str>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        if x.size() != self.ndim {
            return Err("x must have len equal to ndim");
        }
        match self.container_index(x) {
            Some(index) => {
                // new item data
                let mut item = Item {
                    id,
                    x: [x.at(0).into(), x.at(1).into(), 0.0],
                };
                if self.ndim == 3 {
                    item.x[2] = x.at(2).into();
                }

                // update container
                if self.cells.contains_key(&index) {
                    let cell = self.cells.get_mut(&index).unwrap();
                    cell.items.push(item);

                // initialize container
                } else {
                    self.cells.insert(index, Container { items: vec![item] });
                }
            }
            None => return Err("point is outside the grid"),
        }
        Ok(())
    }

    /// Returns a Plot draw this object
    pub fn get_plot(&self) -> Result<Plot, &'static str> {
        let mut xmin = vec![0.0; self.ndim];
        let mut xmax = vec![0.0; self.ndim];
        let mut ndiv = vec![0; self.ndim];
        for i in 0..self.ndim {
            xmin[i] = self.xmin[i];
            xmax[i] = self.xmax[i];
            ndiv[i] = self.ndiv[i];
        }
        let mut shapes = Shapes::new();
        shapes.draw_grid(&xmin, &xmax, &ndiv, true)?;
        let mut plot = Plot::new();
        plot.add(&shapes);
        Ok(plot)
    }

    /// Calculates the container index where the point x should be located
    ///
    /// # Output
    ///
    /// * returns the index of the container or None if the point is out-of-range
    fn container_index<'a, T, U>(&mut self, x: &'a T) -> Option<usize>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        let mut index = 0;
        for i in 0..self.ndim {
            if x.at(i).into() < self.xmin[i] || x.at(i).into() > self.xmax[i] {
                return None;
            }
            self.ratio[i] = ((x.at(i).into() - self.xmin[i]) / self.size[i]) as usize;
            if self.ratio[i] == self.ndiv[i] {
                // the point is exactly on the max edge, thus select inner bin
                self.ratio[i] -= 1; // move to the inside
            }
            index += self.ratio[i] * self.cf[i];
        }
        Some(index)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn new_works() -> Result<(), &'static str> {
        let grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        assert_eq!(grid.ndim, 2);
        assert_eq!(grid.ndiv, [5, 5, 0]);
        assert_eq!(grid.xmin, [-0.2, -0.2, 0.0]);
        assert_eq!(grid.xmax, [0.8, 1.8, 0.0]);
        assert_eq!(grid.xdelta, [1.0, 2.0, 0.0]);
        assert_eq!(grid.size, [0.2, 0.4, 0.0]);
        assert_eq!(grid.cf, [1, 5, 25]);
        assert_eq!(grid.ratio, [0, 0, 0]);
        assert_eq!(grid.cells.len(), 0);
        println!("{:.20}", grid.size[0]);
        Ok(())
    }

    #[test]
    fn container_index_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        let index = grid.container_index(&[0.4, 1.0]).unwrap();
        assert_eq!(index, 13);
        Ok(())
    }

    #[test]
    fn insert_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        grid.insert(33, &[0.4, 1.0])?;
        Ok(())
    }

    #[test]
    fn get_plot_works() -> Result<(), &'static str> {
        let grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        let plot = grid.get_plot()?;
        plot.save("/tmp/gemlab/search_grid_get_plot_works.svg")?;
        Ok(())
    }
}
<commit_msg>Improve draw grid<commit_after>use crate::AsArray1D;
use plotpy::{Curve, Plot, Shapes, Text};
use std::collections::HashMap;

/// Holds the id and coordinates of an item
#[derive(Clone)]
struct Item {
    id: usize,   // identification number
    x: [f64; 3], // coordinates
}

/// Holds items
#[derive(Clone)]
struct Container {
    items: Vec<Item>,
}

/// Implements a grid for fast searching entries by coordinates
///
/// # Reference
///
/// * Durand, Farias, and Pedroso (2015) Computing intersections between
///   non-compatible curves and finite elements, Computational Mechanics;
///   DOI=10.1007/s00466-015-1181-y
pub struct GridSearch {
    // constants
    ndim: usize,      // space dimension
    ndiv: [usize; 3], // number of divisions along each direction
    xmin: [f64; 3],   // min values
    xmax: [f64; 3],   // max values
    xdelta: [f64; 3], // difference between max and min
    size: [f64; 3],   // size of each cell
    cf: [usize; 3],   // coefficients [1, ndiv[0], ndiv[0]*ndiv[1]] (Eq. 8)

    // auxiliary variable
    ratio: [usize; 3], // ratio = trunc(δx[i]/Δx[i]) (Eq. 8)

    // holds non-empty cells. maps cell.id to container
    cells: HashMap<usize, Container>,
}

impl GridSearch {
    /// Creates a new GridSearch
    ///
    /// # Input
    ///
    /// * `xmin, xmax` -- min and max coordinates (len = 2 or 3 == ndim)
    /// * `ndiv` -- number of divisions along each dimension (len = 2 or 3 == ndim)
    pub fn new(xmin: &[f64], xmax: &[f64], ndiv: &[usize]) -> Result<Self, &'static str> {
        // check input
        let ndim = ndiv.len();
        if ndim < 2 || ndim > 3 {
            return Err("ndim must be 2 or 3");
        }
        if xmin.len() != ndim {
            return Err("size of xmin must equal ndim");
        }
        if xmax.len() != ndim {
            return Err("size of xmax must equal ndim");
        }

        // allocate gs
        let mut grid = GridSearch {
            ndim,
            ndiv: [0; 3],
            xmin: [0.0; 3],
            xmax: [0.0; 3],
            xdelta: [0.0; 3],
            size: [0.0; 3],
            ratio: [0; 3],
            cf: [0; 3],
            cells: HashMap::new(),
        };

        // check and compute sizes
        for i in 0..ndim {
            grid.ndiv[i] = ndiv[i];
            if ndiv[i] < 1 {
                return Err("ndiv must be at least 1");
            }
            grid.xmin[i] = xmin[i];
            grid.xmax[i] = xmax[i];
            grid.xdelta[i] = xmax[i] - xmin[i];
            if grid.xdelta[i] <= 0.0 {
                return Err("xmax must be greater than xmin");
            }
            grid.size[i] = grid.xdelta[i] / (ndiv[i] as f64);
        }

        // coefficient
        grid.cf[0] = 1;
        grid.cf[1] = grid.ndiv[0];
        grid.cf[2] = grid.ndiv[0] * grid.ndiv[1];

        // done
        Ok(grid)
    }

    /// Inserts a new item to some container in the grid
    ///
    /// # Input
    ///
    /// * `id` -- identification number for the item
    /// * `x` -- coordinates of the item (an 1D array with len = ndim)
    pub fn insert<'a, T, U>(&mut self, id: usize, x: &'a T) -> Result<(), &'static str>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        if x.size() != self.ndim {
            return Err("x must have len equal to ndim");
        }
        match self.container_index(x) {
            Some(index) => {
                // new item data
                let mut item = Item {
                    id,
                    x: [x.at(0).into(), x.at(1).into(), 0.0],
                };
                if self.ndim == 3 {
                    item.x[2] = x.at(2).into();
                }

                // update container
                if self.cells.contains_key(&index) {
                    let cell = self.cells.get_mut(&index).unwrap();
                    cell.items.push(item);

                // initialize container
                } else {
                    self.cells.insert(index, Container { items: vec![item] });
                }
            }
            None => return Err("point is outside the grid"),
        }
        Ok(())
    }

    /// Returns a drawing of this object
    pub fn plot(&self) -> Result<Plot, &'static str> {
        // create plot
        let mut plot = Plot::new();

        // draw grid
        let mut xmin = vec![0.0; self.ndim];
        let mut xmax = vec![0.0; self.ndim];
        let mut ndiv = vec![0; self.ndim];
        for i in 0..self.ndim {
            xmin[i] = self.xmin[i];
            xmax[i] = self.xmax[i];
            ndiv[i] = self.ndiv[i];
        }
        let mut shapes = Shapes::new();
        shapes
            .set_alt_text_color("#5d5d5d")
            .draw_grid(&xmin, &xmax, &ndiv, false, true)?;
        plot.add(&shapes);

        // draw items
        if self.ndim == 2 {
            let mut curve = Curve::new();
            let mut text = Text::new();
            curve
                .set_marker_style("o")
                .set_marker_color("#fab32faa")
                .set_marker_line_color("black")
                .set_marker_line_width(0.5);
            text.set_color("#cd0000");
            for container in self.cells.values() {
                for item in &container.items {
                    let txt = format!("{}", item.id);
                    curve.draw(&[item.x[0]], &[item.x[1]]);
                    text.draw(item.x[0], item.x[1], &txt);
                }
            }
            plot.add(&curve);
            plot.add(&text);
        }
        Ok(plot)
    }

    /// Calculates the container index where the point x should be located
    ///
    /// # Output
    ///
    /// * returns the index of the container or None if the point is out-of-range
    fn container_index<'a, T, U>(&mut self, x: &'a T) -> Option<usize>
    where
        T: AsArray1D<'a, U>,
        U: 'a + Into<f64>,
    {
        let mut index = 0;
        for i in 0..self.ndim {
            if x.at(i).into() < self.xmin[i] || x.at(i).into() > self.xmax[i] {
                return None;
            }
            self.ratio[i] = ((x.at(i).into() - self.xmin[i]) / self.size[i]) as usize;
            if self.ratio[i] == self.ndiv[i] {
                // the point is exactly on the max edge, thus select inner bin
                self.ratio[i] -= 1; // move to the inside
            }
            index += self.ratio[i] * self.cf[i];
        }
        Some(index)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn new_works() -> Result<(), &'static str> {
        let grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        assert_eq!(grid.ndim, 2);
        assert_eq!(grid.ndiv, [5, 5, 0]);
        assert_eq!(grid.xmin, [-0.2, -0.2, 0.0]);
        assert_eq!(grid.xmax, [0.8, 1.8, 0.0]);
        assert_eq!(grid.xdelta, [1.0, 2.0, 0.0]);
        assert_eq!(grid.size, [0.2, 0.4, 0.0]);
        assert_eq!(grid.cf, [1, 5, 25]);
        assert_eq!(grid.ratio, [0, 0, 0]);
        assert_eq!(grid.cells.len(), 0);
        println!("{:.20}", grid.size[0]);
        assert_eq!(grid.size[0], 0.20000000000000001110); // TODO: check if this is a problem
        let b0 = 0.20000000000000001110_f64.to_bits();
        let b1 = 0.2_f64.to_bits();
        println!("{} =? {}", b0, b1);
        assert_eq!(b0, b1);
        Ok(())
    }

    #[test]
    fn container_index_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        let index = grid.container_index(&[0.4, 1.0]).unwrap();
        assert_eq!(index, 13);
        Ok(())
    }

    #[test]
    fn insert_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        grid.insert(33, &[0.4, 1.0])?;
        Ok(())
    }

    #[test]
    fn plot_works() -> Result<(), &'static str> {
        let mut grid = GridSearch::new(&[-0.2, -0.2], &[0.8, 1.8], &[5, 5])?;
        grid.insert(33, &[0.4, 1.0])?;
        let plot = grid.plot()?;
        plot.save("/tmp/gemlab/search_grid_plot_works.svg")?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate ncurses;

use std::option::Option;
use self::ncurses::*;
use cpu::ExecState;
use instruction;

struct CodeWin {
    wtext:  WINDOW,
    lines:  Vec<String>,
    line:   Option<u8>,
}

impl CodeWin {
    fn new(win: WINDOW, s: &str) -> Self {
        let wtext = derwin(win, TEXT_LINES, TEXT_COLS, 0, 0);
        wbkgd(wtext, '?' as u64);

        let mut codewin = CodeWin {
            wtext: wtext,
            lines: Self::code_vec(s),
            line:  None,
        };

        codewin.set_line(Some(1));
        codewin.draw_all_lines();
        codewin
    }

    fn code_vec(s: &str) -> Vec<String> {
        s.lines().map(str::to_string).collect()
    }

    fn set_code(&mut self, s: &str) {
        self.lines = Self::code_vec(s);
        self.draw_all_lines();
    }

    fn draw_all_lines(&mut self) {
        for i in (0..self.lines.len() as u8) {
            self.draw_line(i);
        }
    }

    fn draw_line(&mut self, line: u8) {
        let mut max_x: i32 = 0;
        let mut max_y: i32 = 0;
        getmaxyx(self.wtext, &mut max_y, &mut max_x);

        if self.line == Some(line) {
            wattr_on(self.wtext, A_STANDOUT());
        }

        let line = line as i32;
        assert!(line < max_y);

        wmove(self.wtext, line, 0);
        wclrtoeol(self.wtext);
        if let Some(s) = self.lines.get(line as usize) {
            mvwprintw(self.wtext, line, 0, s);
        }
        wattr_off(self.wtext, A_STANDOUT());
        wrefresh(self.wtext);
    }

    /// Sets the active (highlighted) line
    fn set_line(&mut self, newline: Option<u8>) {
        let oldline = self.line;
        self.line = newline;

        if let Some(old) = oldline {
            self.draw_line(old);
        }

        if let Some(new) = newline {
            self.draw_line(new);
        }
    }
}

impl Drop for CodeWin {
    fn drop(&mut self) {
        delwin(self.wtext);
    }
}

struct CpuWin {
    win:        WINDOW,
    winner:     WINDOW,
    wsidebar:   WINDOW,
    codewin:    CodeWin,
}

const SIDEBAR_CELL_HEIGHT: i32 = 2;
const SIDEBAR_WIDTH: i32 = 6;
const CPUWIN_HEIGHT: i32 = (SIDEBAR_CELL_HEIGHT + 1) * 4 + 1;
const CPUWIN_WIDTH: i32 = CPUWIN_HEIGHT*2 + SIDEBAR_WIDTH;
const SIDEBAR_X: i32 = CPUWIN_WIDTH - 1 - SIDEBAR_WIDTH - 1;

const TEXT_LINES: i32 = CPUWIN_HEIGHT - 2;
const TEXT_COLS: i32 = CPUWIN_WIDTH - SIDEBAR_WIDTH - 3;

impl CpuWin {
    fn new(posx: i32, posy: i32) -> CpuWin {

        let win = newwin(CPUWIN_HEIGHT, CPUWIN_WIDTH, posy, posx);
        let winner = derwin(win, CPUWIN_HEIGHT-2, CPUWIN_WIDTH-2, 1, 1);
        let wsidebar = derwin(winner, CPUWIN_HEIGHT-2, SIDEBAR_WIDTH, 0, SIDEBAR_X);

        /* Border */
        box_(win, 0, 0);

        /* Left size of sidebar */
        mvwaddch(win, 0, SIDEBAR_X, ACS_TTEE());
        mvwvline(win, 1, SIDEBAR_X, ACS_VLINE(), CPUWIN_HEIGHT - 2);
        mvwaddch(win, CPUWIN_HEIGHT-1, SIDEBAR_X, ACS_BTEE());

        let mut cpuwin = CpuWin {
            win:        win,
            winner:     winner,
            wsidebar:   wsidebar,
            codewin:    CodeWin::new(winner, "line1\nline2\n\nline4"),
        };
        cpuwin.cell_label(0, "ACC");
        cpuwin.cell_label(1, "BAK");
        cpuwin.cell_label(2, "LAST");
        cpuwin.cell_label(3, "MODE");

        cpuwin.cell_divider(1);
        cpuwin.cell_divider(2);
        cpuwin.cell_divider(3);

        cpuwin.set_values(0, 10, None, ExecState::EXEC);

        cpuwin
    }

    fn cell_label(&mut self, cell: i32, l: &str) {
        mvwprintw(self.wsidebar, Self::cell_y(cell), 1, l);
    }

    fn cell_val(&mut self, cell: i32, l: &str) {
        mvwprintw(self.wsidebar, Self::cell_y(cell)+1, 1, l);
    }

    fn cell_divider(&mut self, cell: i32) {
        mvwaddch(self.win, Self::cell_y(cell), SIDEBAR_X, ACS_LTEE());
        mvwhline(self.win, Self::cell_y(cell), SIDEBAR_X+1, ACS_HLINE(), SIDEBAR_WIDTH);
        mvwaddch(self.win, Self::cell_y(cell), SIDEBAR_X+SIDEBAR_WIDTH+1, ACS_RTEE());
    }

    fn cell_y(cell: i32) -> i32 {
        (SIDEBAR_CELL_HEIGHT + 1) * cell
    }

    fn refresh(&mut self) {
        wrefresh(self.win);
    }

    fn set_values(&mut self, acc: i32, bak: i32, last: Option<instruction::Port>, mode: ExecState) {
        let acc = format!("{:^4}", acc);
        let bak = format!("{:^4}", bak);
        let last = last.map_or_else(|| "N/A".to_string(), |p| p.to_string());
        let mode = mode.to_string();
        self.cell_val(0, &acc);
        self.cell_val(1, &bak);
        self.cell_val(2, &last);
        self.cell_val(3, &mode);
    }

    fn set_code(&mut self, s: &str) {
        self.codewin.set_code(s)
    }

    fn set_line(&mut self, newline: Option<u8>) {
        self.codewin.set_line(newline)
    }
}

impl Drop for CpuWin {
    fn drop(&mut self) {
        delwin(self.wsidebar);
        delwin(self.winner);
        wclear(self.win);
        //wrefresh(self.win);
        delwin(self.win);
    }
}

fn create_cpu_wins() -> Vec<Vec<CpuWin>> {
    let left_margin = 10;
    let inner_margin = 4;

    let mut cpuwins: Vec<Vec<CpuWin>> = (0..4).map(|x| {
        (0..3).map(|y| (x, y)).map(|(x, y)| {
            CpuWin::new(x*(CPUWIN_WIDTH + inner_margin) + left_margin,
                        y*(CPUWIN_HEIGHT + inner_margin/2) + left_margin/2)
        }).collect::<Vec<_>>()
    }).collect();

    for y in cpuwins.iter_mut() {
        for cpu in y.iter_mut() {
            cpu.refresh();
        }
    }

    cpuwins
}

pub fn gui() {
    initscr();
    refresh();

    let mut cpuwins = create_cpu_wins();

    loop {
        let c = getch();
        if c == b'q' as i32 {
            break;
        } else if c == KEY_RESIZE {
            drop(cpuwins);
            clear();
            refresh();
            cpuwins = create_cpu_wins();
        } else {
            cpuwins[0][0].set_code("whoo");
            refresh();
        }
    }

    drop(cpuwins);
    endwin();
}
<commit_msg>gui_ncurses: highlight entire line<commit_after>extern crate ncurses;

use std::option::Option;
use std::iter::FromIterator;
use self::ncurses::*;
use cpu::ExecState;
use instruction;

struct CodeWin {
    wtext:  WINDOW,
    lines:  Vec<String>,
    line:   Option<u8>,
}

impl CodeWin {
    fn new(win: WINDOW, s: &str) -> Self {
        let wtext = derwin(win, TEXT_LINES, TEXT_COLS, 0, 0);
        wbkgd(wtext, '?' as u64);

        let mut codewin = CodeWin {
            wtext: wtext,
            lines: Self::code_vec(s),
            line:  None,
        };

        codewin.set_line(Some(1));
        codewin.draw_all_lines();
        codewin
    }

    fn code_vec(s: &str) -> Vec<String> {
        s.lines().map(str::to_string).collect()
    }

    fn set_code(&mut self, s: &str) {
        self.lines = Self::code_vec(s);
        self.draw_all_lines();
    }

    fn draw_all_lines(&mut self) {
        for i in (0..self.lines.len() as u8) {
            self.draw_line(i);
        }
    }

    fn draw_line(&mut self, line: u8) {
        let mut max_x: i32 = 0;
        let mut max_y: i32 = 0;
        getmaxyx(self.wtext, &mut max_y, &mut max_x);

        if self.line == Some(line) {
            wattr_on(self.wtext, A_STANDOUT());
        }

        let line = line as i32;
        assert!(line < max_y);

        wmove(self.wtext, line, 0);
        wclrtoeol(self.wtext);
        wmove(self.wtext, line, 0);
        if let Some(s) = self.lines.get(line as usize) {
            mvwprintw(self.wtext, line, 0, s);
            let pad: usize = TEXT_COLS as usize - s.len();
            wprintw(self.wtext, &String::from_iter([' '].iter().cloned().cycle().take(pad)));
        }
        wattr_off(self.wtext, A_STANDOUT());
        wrefresh(self.wtext);
    }

    /// Sets the active (highlighted) line
    fn set_line(&mut self, newline: Option<u8>) {
        let oldline = self.line;
        self.line = newline;

        if let Some(old) = oldline {
            self.draw_line(old);
        }

        if let Some(new) = newline {
            self.draw_line(new);
        }
    }
}

impl Drop for CodeWin {
    fn drop(&mut self) {
        delwin(self.wtext);
    }
}

struct CpuWin {
    win:        WINDOW,
    winner:     WINDOW,
    wsidebar:   WINDOW,
    codewin:    CodeWin,
}

const SIDEBAR_CELL_HEIGHT: i32 = 2;
const SIDEBAR_WIDTH: i32 = 6;
const CPUWIN_HEIGHT: i32 = (SIDEBAR_CELL_HEIGHT + 1) * 4 + 1;
const CPUWIN_WIDTH: i32 = CPUWIN_HEIGHT*2 + SIDEBAR_WIDTH;
const SIDEBAR_X: i32 = CPUWIN_WIDTH - 1 - SIDEBAR_WIDTH - 1;

const TEXT_LINES: i32 = CPUWIN_HEIGHT - 2;
const TEXT_COLS: i32 = CPUWIN_WIDTH - SIDEBAR_WIDTH - 3;

impl CpuWin {
    fn new(posx: i32, posy: i32) -> CpuWin {

        let win = newwin(CPUWIN_HEIGHT, CPUWIN_WIDTH, posy, posx);
        let winner = derwin(win, CPUWIN_HEIGHT-2, CPUWIN_WIDTH-2, 1, 1);
        let wsidebar = derwin(winner, CPUWIN_HEIGHT-2, SIDEBAR_WIDTH, 0, SIDEBAR_X);

        /* Border */
        box_(win, 0, 0);

        /* Left size of sidebar */
        mvwaddch(win, 0, SIDEBAR_X, ACS_TTEE());
        mvwvline(win, 1, SIDEBAR_X, ACS_VLINE(), CPUWIN_HEIGHT - 2);
        mvwaddch(win, CPUWIN_HEIGHT-1, SIDEBAR_X, ACS_BTEE());

        let mut cpuwin = CpuWin {
            win:        win,
            winner:     winner,
            wsidebar:   wsidebar,
            codewin:    CodeWin::new(winner, "line1\nline2\n\nline4"),
        };
        cpuwin.cell_label(0, "ACC");
        cpuwin.cell_label(1, "BAK");
        cpuwin.cell_label(2, "LAST");
        cpuwin.cell_label(3, "MODE");

        cpuwin.cell_divider(1);
        cpuwin.cell_divider(2);
        cpuwin.cell_divider(3);

        cpuwin.set_values(0, 10, None, ExecState::EXEC);

        cpuwin
    }

    fn cell_label(&mut self, cell: i32, l: &str) {
        mvwprintw(self.wsidebar, Self::cell_y(cell), 1, l);
    }

    fn cell_val(&mut self, cell: i32, l: &str) {
        mvwprintw(self.wsidebar, Self::cell_y(cell)+1, 1, l);
    }

    fn cell_divider(&mut self, cell: i32) {
        mvwaddch(self.win, Self::cell_y(cell), SIDEBAR_X, ACS_LTEE());
        mvwhline(self.win, Self::cell_y(cell), SIDEBAR_X+1, ACS_HLINE(), SIDEBAR_WIDTH);
        mvwaddch(self.win, Self::cell_y(cell), SIDEBAR_X+SIDEBAR_WIDTH+1, ACS_RTEE());
    }

    fn cell_y(cell: i32) -> i32 {
        (SIDEBAR_CELL_HEIGHT + 1) * cell
    }

    fn refresh(&mut self) {
        wrefresh(self.win);
    }

    fn set_values(&mut self, acc: i32, bak: i32, last: Option<instruction::Port>, mode: ExecState) {
        let acc = format!("{:^4}", acc);
        let bak = format!("{:^4}", bak);
        let last = last.map_or_else(|| "N/A".to_string(), |p| p.to_string());
        let mode = mode.to_string();
        self.cell_val(0, &acc);
        self.cell_val(1, &bak);
        self.cell_val(2, &last);
        self.cell_val(3, &mode);
    }

    fn set_code(&mut self, s: &str) {
        self.codewin.set_code(s)
    }

    fn set_line(&mut self, newline: Option<u8>) {
        self.codewin.set_line(newline)
    }
}

impl Drop for CpuWin {
    fn drop(&mut self) {
        delwin(self.wsidebar);
        delwin(self.winner);
        wclear(self.win);
        //wrefresh(self.win);
        delwin(self.win);
    }
}

fn create_cpu_wins() -> Vec<Vec<CpuWin>> {
    let left_margin = 10;
    let inner_margin = 4;

    let mut cpuwins: Vec<Vec<CpuWin>> = (0..4).map(|x| {
        (0..3).map(|y| (x, y)).map(|(x, y)| {
            CpuWin::new(x*(CPUWIN_WIDTH + inner_margin) + left_margin,
                        y*(CPUWIN_HEIGHT + inner_margin/2) + left_margin/2)
        }).collect::<Vec<_>>()
    }).collect();

    for y in cpuwins.iter_mut() {
        for cpu in y.iter_mut() {
            cpu.refresh();
        }
    }

    cpuwins
}

pub fn gui() {
    initscr();
    refresh();

    let mut cpuwins = create_cpu_wins();

    loop {
        let c = getch();
        if c == b'q' as i32 {
            break;
        } else if c == KEY_RESIZE {
            drop(cpuwins);
            clear();
            refresh();
            cpuwins = create_cpu_wins();
        } else {
            cpuwins[0][0].set_code("whoo");
            refresh();
        }
    }

    drop(cpuwins);
    endwin();
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers for reading directory structures from the local filesystem.

use std::fs;
use std::io;
use std::iter;
use std::path::PathBuf;
use std::sync::mpsc;
use std::sync::Arc;

use threadpool;

pub trait HasPath {
    fn path(&self) -> PathBuf;
}

impl HasPath for fs::DirEntry {
    fn path(&self) -> PathBuf {
        fs::DirEntry::path(self)
    }
}

pub trait PathHandler<D>: Send + Sync + 'static {
    type DirItem: HasPath;
    type DirIter: iter::Iterator<Item = io::Result<Self::DirItem>>;

    fn read_dir(&self, &PathBuf) -> io::Result<Self::DirIter>;
    fn handle_path(&self, &D, PathBuf) -> Option<D>;
}

pub fn iterate_recursively<P: Send + 'static, W: PathHandler<P>>(first: (PathBuf, P),
                                                                 worker: Arc<W>) {
    let threads = 10;
    let (push_ch, work_ch) = mpsc::sync_channel(threads);
    let pool = threadpool::ThreadPool::new(threads);

    enum Work<P> {
        Done,
        More(PathBuf, P),
    }

    // Insert the first task into the queue:
    let (root, payload) = first;
    push_ch.send(Work::More(root, payload)).unwrap();
    let worker = Arc::new(worker);
    let mut active_workers = 0;

    // Master thread:
    loop {
        match work_ch.recv() {
            Err(_) => unreachable!(),
            Ok(Work::Done) => {
                // A worker has completed a task.
                // We are done when no more workers are active (i.e. all tasks are done):
                active_workers -= 1;
                if active_workers == 0 {
                    break;
                }
            }
            Ok(Work::More(root, payload)) => {
                // Execute the task in a pool thread:
                active_workers += 1;

                let worker = worker.clone();
                let push_ch_ = push_ch.clone();
                pool.execute(move || {
                    match worker.read_dir(&root) {
                        Ok(dir) => {
                            for entry_res in dir {
                                match entry_res {
                                    Ok(entry) => {
                                        let file = entry.path();
                                        let path = PathBuf::from(file.to_str().unwrap());
                                        let dir_opt = worker.handle_path(&payload, path);
                                        if let Some(dir) = dir_opt {
                                            push_ch_.send(Work::More(file, dir)).unwrap();
                                        }
                                    }
                                    Err(err) => {
                                        // For some reason, we failed to read this entry.
                                        // Just skip it and continue with the next.
                                        warn!("Could not read directory entry: {}", err);
                                    }
                                }
                            }
                        }
                        Err(err) => {
                            // Cannot read this directory.
                            warn!("Skipping unreadable directory {:?}: {}", root, err);
                        }
                    }
                    // Count this pool thread as idle:
                    push_ch_.send(Work::Done).unwrap();
                });
            }
        }
    }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
    fn clone(&self) -> PrintPathHandler {
        PrintPathHandler
    }
}

impl PathHandler<()> for PrintPathHandler {
    type DirItem = fs::DirEntry;
    type DirIter = fs::ReadDir;

    fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
        fs::read_dir(path)
    }

    fn handle_path(&self, _: &(), path: PathBuf) -> Option<()> {
        println!("{}", path.display());
        match fs::metadata(&path) {
            Ok(ref m) if m.is_dir() => Some(()),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {

    use std::collections::btree_map;
    use std::io;
    use std::path::PathBuf;
    use std::sync::{Arc, Mutex};
    use std::vec;

    use super::*;

    type ParentOpt = Option<PathBuf>;
    type VisitedPaths = btree_map::BTreeMap<PathBuf, bool>;

    impl HasPath for PathBuf {
        fn path(&self) -> PathBuf {
            self.to_owned()
        }
    }

    #[derive(Clone)]
    struct StubPathHandler {
        paths: Arc<Mutex<VisitedPaths>>,
    }

    impl StubPathHandler {
        fn new(paths: Vec<PathBuf>) -> StubPathHandler {
            let mut tree = btree_map::BTreeMap::new();
            for path in paths {
                tree.insert(path, false);
            }
            StubPathHandler { paths: Arc::new(Mutex::new(tree)) }
        }

        fn visit(&self, path: PathBuf) -> Option<bool> {
            let mut paths = self.paths.lock().unwrap();
            paths.insert(path, true)
        }

        fn list(&self, dir: &PathBuf) -> vec::IntoIter<io::Result<PathBuf>> {
            let paths = self.paths.lock().unwrap();
            let mut contents = vec![];
            for k in paths.keys() {
                if k.parent() == Some(dir) {
                    contents.push(Ok(k.clone()));
                }
            }
            contents.into_iter()
        }

        fn not_visited(&self) -> Vec<PathBuf> {
            let paths = self.paths.lock().unwrap();
            let mut contents = vec![];
            for (path, visited) in paths.iter() {
                if !visited {
                    contents.push(path.clone());
                }
            }
            contents
        }
    }

    impl PathHandler<ParentOpt> for StubPathHandler {
        type DirItem = PathBuf;
        type DirIter = vec::IntoIter<io::Result<Self::DirItem>>;

        fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
            Ok(self.list(path))
        }

        fn handle_path(&self, p_opt: &ParentOpt, path: PathBuf) -> Option<ParentOpt> {
            assert_eq!(self.visit(path.clone()), Some(false));

            if let &Some(ref p) = p_opt {
                assert!(path.parent() == Some(p));
            }

            self.list(&path).next().map(|_| Some(path))
        }
    }

    #[test]
    fn can_visit_all() {
        let paths: [&str; 20] = ["/",
                                 "/foo",
                                 "/bar/",
                                 "/bar/baz/",
                                 "/bar/baz/qux",
                                 "/bar/baz/foo",
                                 "/bar/baz/bar/",
                                 "/bar/baz/bar/foo",
                                 "/bar/baz/bar/bar/",
                                 "/bar/baz/bar/bar/bar",
                                 "/empty/",
                                 "/empty/1/",
                                 "/empty/2/",
                                 "/empty/3/",
                                 "/empty/4/",
                                 "/empty/5/",
                                 "/empty/6/",
                                 "/empty/7/",
                                 "/empty/8/",
                                 "/empty/9/"];

        let handler = StubPathHandler::new(paths.iter().map(PathBuf::from).collect());
        let handler = Arc::new(handler);
        iterate_recursively((PathBuf::from("/"), None), handler.clone());

        assert_eq!(handler.not_visited(), vec![PathBuf::from("/")]);
    }

}
<commit_msg>Removed an extra Arc<> in PathHandler test<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers for reading directory structures from the local filesystem.

use std::fs;
use std::io;
use std::iter;
use std::path::PathBuf;
use std::sync::mpsc;
use std::sync::Arc;

use threadpool;

pub trait HasPath {
    fn path(&self) -> PathBuf;
}

impl HasPath for fs::DirEntry {
    fn path(&self) -> PathBuf {
        fs::DirEntry::path(self)
    }
}

pub trait PathHandler<D>: Send + Sync + 'static {
    type DirItem: HasPath;
    type DirIter: iter::Iterator<Item = io::Result<Self::DirItem>>;

    fn read_dir(&self, &PathBuf) -> io::Result<Self::DirIter>;
    fn handle_path(&self, &D, PathBuf) -> Option<D>;
}

pub fn iterate_recursively<P: Send + 'static, W: PathHandler<P>>(first: (PathBuf, P),
                                                                 worker: Arc<W>) {
    let threads = 10;
    let (push_ch, work_ch) = mpsc::sync_channel(threads);
    let pool = threadpool::ThreadPool::new(threads);

    enum Work<P> {
        Done,
        More(PathBuf, P),
    }

    // Insert the first task into the queue:
    let (root, payload) = first;
    push_ch.send(Work::More(root, payload)).unwrap();
    let worker = Arc::new(worker);
    let mut active_workers = 0;

    // Master thread:
    loop {
        match work_ch.recv() {
            Err(_) => unreachable!(),
            Ok(Work::Done) => {
                // A worker has completed a task.
                // We are done when no more workers are active (i.e. all tasks are done):
                active_workers -= 1;
                if active_workers == 0 {
                    break;
                }
            }
            Ok(Work::More(root, payload)) => {
                // Execute the task in a pool thread:
                active_workers += 1;

                let worker = worker.clone();
                let push_ch_ = push_ch.clone();
                pool.execute(move || {
                    match worker.read_dir(&root) {
                        Ok(dir) => {
                            for entry_res in dir {
                                match entry_res {
                                    Ok(entry) => {
                                        let file = entry.path();
                                        let path = PathBuf::from(file.to_str().unwrap());
                                        let dir_opt = worker.handle_path(&payload, path);
                                        if let Some(dir) = dir_opt {
                                            push_ch_.send(Work::More(file, dir)).unwrap();
                                        }
                                    }
                                    Err(err) => {
                                        // For some reason, we failed to read this entry.
                                        // Just skip it and continue with the next.
                                        warn!("Could not read directory entry: {}", err);
                                    }
                                }
                            }
                        }
                        Err(err) => {
                            // Cannot read this directory.
                            warn!("Skipping unreadable directory {:?}: {}", root, err);
                        }
                    }
                    // Count this pool thread as idle:
                    push_ch_.send(Work::Done).unwrap();
                });
            }
        }
    }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
    fn clone(&self) -> PrintPathHandler {
        PrintPathHandler
    }
}

impl PathHandler<()> for PrintPathHandler {
    type DirItem = fs::DirEntry;
    type DirIter = fs::ReadDir;

    fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
        fs::read_dir(path)
    }

    fn handle_path(&self, _: &(), path: PathBuf) -> Option<()> {
        println!("{}", path.display());
        match fs::metadata(&path) {
            Ok(ref m) if m.is_dir() => Some(()),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {

    use std::collections::btree_map;
    use std::io;
    use std::path::PathBuf;
    use std::sync::{Arc, Mutex};
    use std::vec;

    use super::*;

    type ParentOpt = Option<PathBuf>;
    type VisitedPaths = btree_map::BTreeMap<PathBuf, bool>;

    impl HasPath for PathBuf {
        fn path(&self) -> PathBuf {
            self.to_owned()
        }
    }

    struct StubPathHandler {
        paths: Mutex<VisitedPaths>,
    }

    impl StubPathHandler {
        fn new(paths: Vec<PathBuf>) -> StubPathHandler {
            let mut tree = btree_map::BTreeMap::new();
            for path in paths {
                tree.insert(path, false);
            }
            StubPathHandler { paths: Mutex::new(tree) }
        }

        fn visit(&self, path: PathBuf) -> Option<bool> {
            let mut paths = self.paths.lock().unwrap();
            paths.insert(path, true)
        }

        fn list(&self, dir: &PathBuf) -> vec::IntoIter<io::Result<PathBuf>> {
            let paths = self.paths.lock().unwrap();
            let mut contents = vec![];
            for k in paths.keys() {
                if k.parent() == Some(dir) {
                    contents.push(Ok(k.clone()));
                }
            }
            contents.into_iter()
        }

        fn not_visited(&self) -> Vec<PathBuf> {
            let paths = self.paths.lock().unwrap();
            let mut contents = vec![];
            for (path, visited) in paths.iter() {
                if !visited {
                    contents.push(path.clone());
                }
            }
            contents
        }
    }

    impl PathHandler<ParentOpt> for StubPathHandler {
        type DirItem = PathBuf;
        type DirIter = vec::IntoIter<io::Result<Self::DirItem>>;

        fn read_dir(&self, path: &PathBuf) -> io::Result<Self::DirIter> {
            Ok(self.list(path))
        }

        fn handle_path(&self, p_opt: &ParentOpt, path: PathBuf) -> Option<ParentOpt> {
            assert_eq!(self.visit(path.clone()), Some(false));

            if let &Some(ref p) = p_opt {
                assert!(path.parent() == Some(p));
            }

            self.list(&path).next().map(|_| Some(path))
        }
    }

    #[test]
    fn can_visit_all() {
        let paths: [&str; 20] = ["/",
                                 "/foo",
                                 "/bar/",
                                 "/bar/baz/",
                                 "/bar/baz/qux",
                                 "/bar/baz/foo",
                                 "/bar/baz/bar/",
                                 "/bar/baz/bar/foo",
                                 "/bar/baz/bar/bar/",
                                 "/bar/baz/bar/bar/bar",
                                 "/empty/",
                                 "/empty/1/",
                                 "/empty/2/",
                                 "/empty/3/",
                                 "/empty/4/",
                                 "/empty/5/",
                                 "/empty/6/",
                                 "/empty/7/",
                                 "/empty/8/",
                                 "/empty/9/"];

        let handler = StubPathHandler::new(paths.iter().map(PathBuf::from).collect());
        let handler = Arc::new(handler);
        iterate_recursively((PathBuf::from("/"), None), handler.clone());

        assert_eq!(handler.not_visited(), vec![PathBuf::from("/")]);
    }

}
<|endoftext|>


<commit_before>use crate::context::Context;
use crate::error::RenderError;
use crate::json::value::ScopedJson;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{do_escape, Helper, RenderContext};

pub use self::helper_each::EACH_HELPER;
pub use self::helper_if::{IF_HELPER, UNLESS_HELPER};
pub use self::helper_log::LOG_HELPER;
pub use self::helper_lookup::LOOKUP_HELPER;
pub use self::helper_raw::RAW_HELPER;
pub use self::helper_with::WITH_HELPER;

/// A type alias for `Result<(), RenderError>`
pub type HelperResult = Result<(), RenderError>;

/// Helper Definition
///
/// Implement `HelperDef` to create custom helpers. You can retrieve useful information from these arguments.
///
/// * `&Helper`: current helper template information, contains name, params, hashes and nested template
/// * `&Registry`: the global registry, you can find templates by name from registry
/// * `&Context`: the whole data to render, in most case you can use data from `Helper`
/// * `&mut RenderContext`: you can access data or modify variables (starts with @)/partials in render context, for example, @index of #each. See its document for detail.
/// * `&mut dyn Output`: where you write output to
///
/// By default, you can use a bare function as a helper definition because we have supported unboxed_closure. If you have stateful or configurable helper, you can create a struct to implement `HelperDef`.
///
/// ## Define an inline helper
///
/// ```
/// use handlebars::*;
///
/// fn upper(h: &Helper<'_, '_>, _: &Handlebars<'_>, _: &Context, rc: &mut RenderContext<'_, '_>, out: &mut Output)
///     -> HelperResult {
///    // get parameter from helper or throw an error
///    let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or("");
///    out.write(param.to_uppercase().as_ref())?;
///    Ok(())
/// }
/// ```
///
/// ## Define block helper
///
/// Block helper is like `#if` or `#each` which has a inner template and an optional *inverse* template (the template in else branch). You can access the inner template by `helper.template()` and `helper.inverse()`. In most cases you will just call `render` on it.
///
/// ```
/// use handlebars::*;
///
/// fn dummy_block<'reg, 'rc>(
///     h: &Helper<'reg, 'rc>,
///     r: &'reg Handlebars<'reg>,
///     ctx: &'rc Context,
///     rc: &mut RenderContext<'reg, 'rc>,
///     out: &mut dyn Output,
/// ) -> HelperResult {
///     h.template()
///         .map(|t| t.render(r, ctx, rc, out))
///         .unwrap_or(Ok(()))
/// }
/// ```
///
/// ## Define helper function using macro
///
/// In most cases you just need some simple function to call from templates. We have a `handlebars_helper!` macro to simplify the job.
///
/// ```
/// use handlebars::*;
///
/// handlebars_helper!(plus: |x: i64, y: i64| x + y);
///
/// let mut hbs = Handlebars::new();
/// hbs.register_helper("plus", Box::new(plus));
/// ```
///

pub trait HelperDef {
    fn call_inner<'reg: 'rc, 'rc>(
        &self,
        _: &Helper<'reg, 'rc>,
        _: &'reg Registry<'reg>,
        _: &'rc Context,
        _: &mut RenderContext<'reg, 'rc>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        Err(RenderError::unimplemented())
    }

    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        match self.call_inner(h, r, ctx, rc) {
            Ok(result) => {
                if r.strict_mode() && result.is_missing() {
                    return Err(RenderError::strict_error(None));
                } else {
                    // auto escape according to settings
                    let output = do_escape(r, rc, result.render());
                    out.write(output.as_ref())?;
                    Ok(())
                }
            }
            Err(e) => {
                if e.is_unimplemented() {
                    // default implementation, do nothing
                    Ok(())
                } else {
                    Err(e)
                }
            }
        }
    }
}

/// implement HelperDef for bare function so we can use function as helper
impl<
        F: for<'reg, 'rc> Fn(
            &Helper<'reg, 'rc>,
            &'reg Registry<'reg>,
            &'rc Context,
            &mut RenderContext<'reg, 'rc>,
            &mut dyn Output,
        ) -> HelperResult,
    > HelperDef for F
{
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        (*self)(h, r, ctx, rc, out)
    }
}

mod block_util;
mod helper_each;
pub(crate) mod helper_extras;
mod helper_if;
mod helper_log;
mod helper_lookup;
mod helper_raw;
mod helper_with;
#[cfg(feature = "script_helper")]
pub(crate) mod scripting;

// pub type HelperDef = for <'a, 'b, 'c> Fn<(&'a Context, &'b Helper, &'b Registry, &'c mut RenderContext), Result<String, RenderError>>;
//
// pub fn helper_dummy (ctx: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
// h.template().unwrap().render(ctx, r, rc).unwrap()
// }
//
#[cfg(test)]
mod test {
    use std::collections::BTreeMap;

    use crate::context::Context;
    use crate::error::RenderError;
    use crate::helpers::HelperDef;
    use crate::json::value::JsonRender;
    use crate::output::Output;
    use crate::registry::Registry;
    use crate::render::{Helper, RenderContext, Renderable};

    #[derive(Clone, Copy)]
    struct MetaHelper;

    impl HelperDef for MetaHelper {
        fn call<'reg: 'rc, 'rc>(
            &self,
            h: &Helper<'reg, 'rc>,
            r: &'reg Registry<'reg>,
            ctx: &'rc Context,
            rc: &mut RenderContext<'reg, 'rc>,
            out: &mut dyn Output,
        ) -> Result<(), RenderError> {
            let v = h.param(0).unwrap();

            if !h.is_block() {
                let output = format!("{}:{}", h.name(), v.value().render());
                out.write(output.as_ref())?;
            } else {
                let output = format!("{}:{}", h.name(), v.value().render());
                out.write(output.as_ref())?;
                out.write("->")?;
                h.template().unwrap().render(r, ctx, rc, out)?;
            };
            Ok(())
        }
    }

    #[test]
    fn test_meta_helper() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{foo this}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#bar this}}nice{{/bar}}")
            .is_ok());

        let meta_helper = MetaHelper;
        handlebars.register_helper("helperMissing", Box::new(meta_helper));
        handlebars.register_helper("blockHelperMissing", Box::new(meta_helper));

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.ok().unwrap(), "foo:true".to_string());

        let r1 = handlebars.render("t1", &true);
        assert_eq!(r1.ok().unwrap(), "bar:true->nice".to_string());
    }

    #[test]
    fn test_helper_for_subexpression() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t2", "{{foo value=(bar 0)}}")
            .is_ok());

        handlebars.register_helper(
            "helperMissing",
            Box::new(
                |h: &Helper<'_, '_>,
                 _: &Registry<'_>,
                 _: &Context,
                 _: &mut RenderContext<'_, '_>,
                 out: &mut dyn Output|
                 -> Result<(), RenderError> {
                    let output = format!("{}{}", h.name(), h.param(0).unwrap().value());
                    out.write(output.as_ref())?;
                    Ok(())
                },
            ),
        );
        handlebars.register_helper(
            "foo",
            Box::new(
                |h: &Helper<'_, '_>,
                 _: &Registry<'_>,
                 _: &Context,
                 _: &mut RenderContext<'_, '_>,
                 out: &mut dyn Output|
                 -> Result<(), RenderError> {
                    let output = format!("{}", h.hash_get("value").unwrap().value().render());
                    out.write(output.as_ref())?;
                    Ok(())
                },
            ),
        );

        let mut data = BTreeMap::new();
        // handlebars should never try to lookup this value because
        // subexpressions are now resolved as string literal
        data.insert("bar0".to_string(), true);

        let r2 = handlebars.render("t2", &data);

        assert_eq!(r2.ok().unwrap(), "bar0".to_string());
    }
}
<commit_msg>(fix) clippy warnings<commit_after>use crate::context::Context;
use crate::error::RenderError;
use crate::json::value::ScopedJson;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{do_escape, Helper, RenderContext};

pub use self::helper_each::EACH_HELPER;
pub use self::helper_if::{IF_HELPER, UNLESS_HELPER};
pub use self::helper_log::LOG_HELPER;
pub use self::helper_lookup::LOOKUP_HELPER;
pub use self::helper_raw::RAW_HELPER;
pub use self::helper_with::WITH_HELPER;

/// A type alias for `Result<(), RenderError>`
pub type HelperResult = Result<(), RenderError>;

/// Helper Definition
///
/// Implement `HelperDef` to create custom helpers. You can retrieve useful information from these arguments.
///
/// * `&Helper`: current helper template information, contains name, params, hashes and nested template
/// * `&Registry`: the global registry, you can find templates by name from registry
/// * `&Context`: the whole data to render, in most case you can use data from `Helper`
/// * `&mut RenderContext`: you can access data or modify variables (starts with @)/partials in render context, for example, @index of #each. See its document for detail.
/// * `&mut dyn Output`: where you write output to
///
/// By default, you can use a bare function as a helper definition because we have supported unboxed_closure. If you have stateful or configurable helper, you can create a struct to implement `HelperDef`.
///
/// ## Define an inline helper
///
/// ```
/// use handlebars::*;
///
/// fn upper(h: &Helper<'_, '_>, _: &Handlebars<'_>, _: &Context, rc: &mut RenderContext<'_, '_>, out: &mut Output)
///     -> HelperResult {
///    // get parameter from helper or throw an error
///    let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or("");
///    out.write(param.to_uppercase().as_ref())?;
///    Ok(())
/// }
/// ```
///
/// ## Define block helper
///
/// Block helper is like `#if` or `#each` which has a inner template and an optional *inverse* template (the template in else branch). You can access the inner template by `helper.template()` and `helper.inverse()`. In most cases you will just call `render` on it.
///
/// ```
/// use handlebars::*;
///
/// fn dummy_block<'reg, 'rc>(
///     h: &Helper<'reg, 'rc>,
///     r: &'reg Handlebars<'reg>,
///     ctx: &'rc Context,
///     rc: &mut RenderContext<'reg, 'rc>,
///     out: &mut dyn Output,
/// ) -> HelperResult {
///     h.template()
///         .map(|t| t.render(r, ctx, rc, out))
///         .unwrap_or(Ok(()))
/// }
/// ```
///
/// ## Define helper function using macro
///
/// In most cases you just need some simple function to call from templates. We have a `handlebars_helper!` macro to simplify the job.
///
/// ```
/// use handlebars::*;
///
/// handlebars_helper!(plus: |x: i64, y: i64| x + y);
///
/// let mut hbs = Handlebars::new();
/// hbs.register_helper("plus", Box::new(plus));
/// ```
///

pub trait HelperDef {
    fn call_inner<'reg: 'rc, 'rc>(
        &self,
        _: &Helper<'reg, 'rc>,
        _: &'reg Registry<'reg>,
        _: &'rc Context,
        _: &mut RenderContext<'reg, 'rc>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        Err(RenderError::unimplemented())
    }

    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        match self.call_inner(h, r, ctx, rc) {
            Ok(result) => {
                if r.strict_mode() && result.is_missing() {
                    Err(RenderError::strict_error(None))
                } else {
                    // auto escape according to settings
                    let output = do_escape(r, rc, result.render());
                    out.write(output.as_ref())?;
                    Ok(())
                }
            }
            Err(e) => {
                if e.is_unimplemented() {
                    // default implementation, do nothing
                    Ok(())
                } else {
                    Err(e)
                }
            }
        }
    }
}

/// implement HelperDef for bare function so we can use function as helper
impl<
        F: for<'reg, 'rc> Fn(
            &Helper<'reg, 'rc>,
            &'reg Registry<'reg>,
            &'rc Context,
            &mut RenderContext<'reg, 'rc>,
            &mut dyn Output,
        ) -> HelperResult,
    > HelperDef for F
{
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        (*self)(h, r, ctx, rc, out)
    }
}

mod block_util;
mod helper_each;
pub(crate) mod helper_extras;
mod helper_if;
mod helper_log;
mod helper_lookup;
mod helper_raw;
mod helper_with;
#[cfg(feature = "script_helper")]
pub(crate) mod scripting;

// pub type HelperDef = for <'a, 'b, 'c> Fn<(&'a Context, &'b Helper, &'b Registry, &'c mut RenderContext), Result<String, RenderError>>;
//
// pub fn helper_dummy (ctx: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
// h.template().unwrap().render(ctx, r, rc).unwrap()
// }
//
#[cfg(test)]
mod test {
    use std::collections::BTreeMap;

    use crate::context::Context;
    use crate::error::RenderError;
    use crate::helpers::HelperDef;
    use crate::json::value::JsonRender;
    use crate::output::Output;
    use crate::registry::Registry;
    use crate::render::{Helper, RenderContext, Renderable};

    #[derive(Clone, Copy)]
    struct MetaHelper;

    impl HelperDef for MetaHelper {
        fn call<'reg: 'rc, 'rc>(
            &self,
            h: &Helper<'reg, 'rc>,
            r: &'reg Registry<'reg>,
            ctx: &'rc Context,
            rc: &mut RenderContext<'reg, 'rc>,
            out: &mut dyn Output,
        ) -> Result<(), RenderError> {
            let v = h.param(0).unwrap();

            if !h.is_block() {
                let output = format!("{}:{}", h.name(), v.value().render());
                out.write(output.as_ref())?;
            } else {
                let output = format!("{}:{}", h.name(), v.value().render());
                out.write(output.as_ref())?;
                out.write("->")?;
                h.template().unwrap().render(r, ctx, rc, out)?;
            };
            Ok(())
        }
    }

    #[test]
    fn test_meta_helper() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{foo this}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#bar this}}nice{{/bar}}")
            .is_ok());

        let meta_helper = MetaHelper;
        handlebars.register_helper("helperMissing", Box::new(meta_helper));
        handlebars.register_helper("blockHelperMissing", Box::new(meta_helper));

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.ok().unwrap(), "foo:true".to_string());

        let r1 = handlebars.render("t1", &true);
        assert_eq!(r1.ok().unwrap(), "bar:true->nice".to_string());
    }

    #[test]
    fn test_helper_for_subexpression() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t2", "{{foo value=(bar 0)}}")
            .is_ok());

        handlebars.register_helper(
            "helperMissing",
            Box::new(
                |h: &Helper<'_, '_>,
                 _: &Registry<'_>,
                 _: &Context,
                 _: &mut RenderContext<'_, '_>,
                 out: &mut dyn Output|
                 -> Result<(), RenderError> {
                    let output = format!("{}{}", h.name(), h.param(0).unwrap().value());
                    out.write(output.as_ref())?;
                    Ok(())
                },
            ),
        );
        handlebars.register_helper(
            "foo",
            Box::new(
                |h: &Helper<'_, '_>,
                 _: &Registry<'_>,
                 _: &Context,
                 _: &mut RenderContext<'_, '_>,
                 out: &mut dyn Output|
                 -> Result<(), RenderError> {
                    let output = format!("{}", h.hash_get("value").unwrap().value().render());
                    out.write(output.as_ref())?;
                    Ok(())
                },
            ),
        );

        let mut data = BTreeMap::new();
        // handlebars should never try to lookup this value because
        // subexpressions are now resolved as string literal
        data.insert("bar0".to_string(), true);

        let r2 = handlebars.render("t2", &data);

        assert_eq!(r2.ok().unwrap(), "bar0".to_string());
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate multipart_async;

use multipart_async::client::*;

use std::io;

fn main() {
    let mut stdout = io::stdout();

    let stream: Vec<_> = (0u8 .. 32).collect();

    let mut multipart = chained! {
        "text" => text("Hello, world!"),
        "file" => file("lorem_ipsum.txt"),
        /* "binary" => stream((io::Cursor::new(stream))) */
    };

    while let RequestStatus::MoreData = multipart.on_writable(&mut stdout).unwrap() {}
}

<commit_msg>Reactivate binary field<commit_after>#[macro_use] extern crate multipart_async;

use multipart_async::client::*;

use std::io;

fn main() {
    let mut stdout = io::stdout();

    let stream: Vec<_> = (0u8 .. 32).collect();

    let mut multipart = chained! {
        "text" => text("Hello, world!"),
        "file" => file("lorem_ipsum.txt"),
        "binary" => stream((io::Cursor::new(stream))),
    };

    while let RequestStatus::MoreData = multipart.on_writable(&mut stdout).unwrap() {}
}

<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
}

impl<'a> Term<'a> {
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        let total_lines = editor.contents.len();
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: total_lines,
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        self.print_file();
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x >= self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self) {
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            for b in line {
                self.term[(j, i)].set_ch(*b as char);
                j += 1;
            }
            i += 1;
            j = 0;
            if i == self.term.rows() - 2 {
                break;
            }
        }
    }

    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                } else if self.current_line() != 0 {
                    let current_line = self.current_line();
                    self.set_current_line(current_line - 1);
                    self.redraw_file();
                }
            }
            cursor::Direction::Down => {
                if self.total_lines() <= self.term.rows() - 3 {
                    if self.cursor.pos.y != self.term.rows() - 3 &&
                       self.cursor.pos.y < self.total_lines() - 1
                    {
                        self.cursor.save_pos();
                        self.cursor.pos.y += 1;
                    }
                } else {
                    if self.cursor.pos.y != self.term.rows() - 3 {
                        self.cursor.save_pos();
                        self.cursor.pos.y += 1;
                    } else if self.cursor.pos.y + self.current_line() < self.total_lines() {
                        let current_line = self.current_line();
                        self.set_current_line(current_line + 1);
                        self.redraw_file();
                    }
                }
            }
            cursor::Direction::Left => {
                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                }
            }
            cursor::Direction::Right => {
                // TODO(nokaa): We don't want to extend beyond the
                // line length here, but we first need a way to
                // determine a given line's length.
                self.cursor.save_pos();
                self.cursor.pos.x += 1;
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        println!("redraw!");
    }
}
<commit_msg>Right movement no longer extends beyond line length<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
}

impl<'a> Term<'a> {
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        let total_lines = editor.contents.len();
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: total_lines,
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        self.print_file();
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x >= self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self) {
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            for b in line {
                self.term[(j, i)].set_ch(*b as char);
                j += 1;
            }
            i += 1;
            j = 0;
            if i == self.term.rows() - 2 {
                break;
            }
        }
    }

    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                } else if self.current_line() != 0 {
                    let current_line = self.current_line();
                    self.set_current_line(current_line - 1);
                    self.redraw_file();
                }
            }
            cursor::Direction::Down => {
                if self.total_lines() <= self.term.rows() - 3 {
                    if self.cursor.pos.y != self.term.rows() - 3 &&
                       self.cursor.pos.y < self.total_lines() - 1
                    {
                        self.cursor.save_pos();
                        self.cursor.pos.y += 1;
                    }
                } else {
                    if self.cursor.pos.y != self.term.rows() - 3 {
                        self.cursor.save_pos();
                        self.cursor.pos.y += 1;
                    } else if self.cursor.pos.y + self.current_line() < self.total_lines() {
                        let current_line = self.current_line();
                        self.set_current_line(current_line + 1);
                        self.redraw_file();
                    }
                }
            }
            cursor::Direction::Left => {
                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                }
            }
            cursor::Direction::Right => {
                // TODO(nokaa): We don't want to extend beyond the
                // line length here, but we first need a way to
                // determine a given line's length.
                let curr = self.cursor.pos.y + self.current_line();
                if self.cursor.pos.x != self.editor.contents[curr].len() - 1 {
                    self.cursor.save_pos();
                    self.cursor.pos.x += 1;
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        println!("redraw!");
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::from_str::FromStr;

/// HTTP methods, as defined in RFC 2616, §5.1.1.
///
/// Method names are case-sensitive.
#[deriving(PartialEq, Eq, Clone)]
pub enum Method {
    Options,
    Get,
    Head,
    Post,
    Put,
    Delete,
    Trace,
    Connect,
    Patch,  // RFC 5789
    ExtensionMethod(String),
}

impl FromStr for Method {
    /**
     * Get a *known* `Method` from an *ASCII* string, regardless of case.
     *
     * If you want to support unregistered methods, use `from_str_or_new` instead.
     *
     * (If the string isn't ASCII, this will at present fail: TODO fix that.)
     */
    fn from_str(method: &str) -> Option<Method> {
        if !method.is_ascii() {
            return None;
        }
        match method {
            "OPTIONS" => Some(Options),
            "GET"     => Some(Get),
            "HEAD"    => Some(Head),
            "POST"    => Some(Post),
            "PUT"     => Some(Put),
            "DELETE"  => Some(Delete),
            "TRACE"   => Some(Trace),
            "CONNECT" => Some(Connect),
            "PATCH"   => Some(Patch),
            _         => None
        }
    }
}

impl fmt::Show for Method {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write(match *self {
            Options                => b"OPTIONS",
            Get                    => b"GET",
            Head                   => b"HEAD",
            Post                   => b"POST",
            Put                    => b"PUT",
            Delete                 => b"DELETE",
            Trace                  => b"TRACE",
            Connect                => b"CONNECT",
            Patch                  => b"PATCH",
            ExtensionMethod(ref s) => s.as_bytes(),
        })
    }
}

impl Method {
    /**
     * Get a `Method` from an *ASCII* string.
     *
     * (If the string isn't ASCII, this will at present fail.)
     */
    pub fn from_str_or_new(method: &str) -> Option<Method> {
        assert!(method.is_ascii());
        Some(match method {
            "OPTIONS" => Options,
            "GET"     => Get,
            "HEAD"    => Head,
            "POST"    => Post,
            "PUT"     => Put,
            "DELETE"  => Delete,
            "TRACE"   => Trace,
            "CONNECT" => Connect,
            "PATCH"   => Patch,
            _         => ExtensionMethod(String::from_str(method)),
        })
    }
}
<commit_msg>Derive Hash for Method.<commit_after>use std::fmt;
use std::from_str::FromStr;

/// HTTP methods, as defined in RFC 2616, §5.1.1.
///
/// Method names are case-sensitive.
#[deriving(PartialEq, Eq, Clone, Hash)]
pub enum Method {
    Options,
    Get,
    Head,
    Post,
    Put,
    Delete,
    Trace,
    Connect,
    Patch,  // RFC 5789
    ExtensionMethod(String),
}

impl FromStr for Method {
    /**
     * Get a *known* `Method` from an *ASCII* string, regardless of case.
     *
     * If you want to support unregistered methods, use `from_str_or_new` instead.
     *
     * (If the string isn't ASCII, this will at present fail: TODO fix that.)
     */
    fn from_str(method: &str) -> Option<Method> {
        if !method.is_ascii() {
            return None;
        }
        match method {
            "OPTIONS" => Some(Options),
            "GET"     => Some(Get),
            "HEAD"    => Some(Head),
            "POST"    => Some(Post),
            "PUT"     => Some(Put),
            "DELETE"  => Some(Delete),
            "TRACE"   => Some(Trace),
            "CONNECT" => Some(Connect),
            "PATCH"   => Some(Patch),
            _         => None
        }
    }
}

impl fmt::Show for Method {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write(match *self {
            Options                => b"OPTIONS",
            Get                    => b"GET",
            Head                   => b"HEAD",
            Post                   => b"POST",
            Put                    => b"PUT",
            Delete                 => b"DELETE",
            Trace                  => b"TRACE",
            Connect                => b"CONNECT",
            Patch                  => b"PATCH",
            ExtensionMethod(ref s) => s.as_bytes(),
        })
    }
}

impl Method {
    /**
     * Get a `Method` from an *ASCII* string.
     *
     * (If the string isn't ASCII, this will at present fail.)
     */
    pub fn from_str_or_new(method: &str) -> Option<Method> {
        assert!(method.is_ascii());
        Some(match method {
            "OPTIONS" => Options,
            "GET"     => Get,
            "HEAD"    => Head,
            "POST"    => Post,
            "PUT"     => Put,
            "DELETE"  => Delete,
            "TRACE"   => Trace,
            "CONNECT" => Connect,
            "PATCH"   => Patch,
            _         => ExtensionMethod(String::from_str(method)),
        })
    }
}
<|endoftext|>


<commit_before>use crate::spec::{LldFlavor, LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
    let mut base = super::hermit_kernel_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);
    base.features = "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float".to_string();
    base.stack_probes = true;

    Ok(Target {
        llvm_target: "x86_64-unknown-hermit".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "64".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
        arch: "x86_64".to_string(),
        target_os: "hermit".to_string(),
        target_env: String::new(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        options: base,
    })
}
<commit_msg>use nicer code style to pass tidy check<commit_after>use crate::spec::{LldFlavor, LinkerFlavor, Target, TargetResult};

pub fn target() -> TargetResult {
    let mut base = super::hermit_kernel_base::opts();
    base.cpu = "x86-64".to_string();
    base.max_atomic_width = Some(64);
    base.features =
        "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
        .to_string();
    base.stack_probes = true;

    Ok(Target {
        llvm_target: "x86_64-unknown-hermit".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "64".to_string(),
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
        arch: "x86_64".to_string(),
        target_os: "hermit".to_string(),
        target_env: String::new(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        options: base,
    })
}
<|endoftext|>