<commit_before>#[deriving(PartialEq, Eq)]
enum TextureType {
    Regular,
    Compressed,
    Integral,
    Unsigned,
}

#[deriving(PartialEq, Eq)]
enum TextureDimensions {
    Texture1d,
    Texture2d,
    Texture3d,
    Texture1dArray,
    Texture2dArray,
}

pub fn build_texture_file<W: Writer>(mut dest: &mut W) {
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture2dArray);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture2dArray);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture2dArray);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2dArray);
}

fn build_texture<W: Writer>(mut dest: &mut W, ty: TextureType, dimensions: TextureDimensions) {
    // building the name of the texture type
    let name: String = {
        let prefix = match ty {
            TextureType::Regular => "",
            TextureType::Compressed => "Compressed",
            TextureType::Integral => "Integral",
            TextureType::Unsigned => "Unsigned",
        };

        let suffix = match dimensions {
            TextureDimensions::Texture1d => "Texture1d",
            TextureDimensions::Texture2d => "Texture2d",
            TextureDimensions::Texture3d => "Texture3d",
            TextureDimensions::Texture1dArray => "Texture1dArray",
            TextureDimensions::Texture2dArray => "Texture2dArray",
        };

        format!("{}{}", prefix, suffix)
    };

    // writing the struct with doc-comment
    (write!(dest, "/// ")).unwrap();
    (write!(dest, "{}", match dimensions {
        TextureDimensions::Texture1d | TextureDimensions::Texture2d |
        TextureDimensions::Texture3d => "A ",
        TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "An array of ",
    })).unwrap();
    if ty == TextureType::Compressed {
        (write!(dest, "compressed ")).unwrap();
    }
    (write!(dest, "{}", match dimensions {
        TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => "one-dimensional ",
        TextureDimensions::Texture2d | TextureDimensions::Texture2dArray => "two-dimensional ",
        TextureDimensions::Texture3d => "three-dimensional ",
    })).unwrap();
    (write!(dest, "{}", match dimensions {
        TextureDimensions::Texture1d | TextureDimensions::Texture2d |
        TextureDimensions::Texture3d => "texture ",
        TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "textures ",
    })).unwrap();
    (write!(dest, "{}", match ty {
        TextureType::Regular | TextureType::Compressed => " containing floating-point data",
        TextureType::Integral => " containing signed integral data",
        TextureType::Unsigned => " containing unsigned integral data",
    })).unwrap();
    (writeln!(dest, ".")).unwrap();
    (writeln!(dest, "pub struct {}(TextureImplementation);", name)).unwrap();

    // `Texture` trait impl
    (writeln!(dest, "
                impl Texture for {} {{
                    fn get_implementation(&self) -> &TextureImplementation {{
                        &self.0
                    }}
                }}
            ", name)).unwrap();

    // `UniformValue` trait impl
    (writeln!(dest, "
                impl<'a> UniformValue for &'a {} {{
                    fn to_binder(&self) -> UniformValueBinder {{
                        self.get_implementation().to_binder()
                    }}
                }}
            ", name)).unwrap();

    // opening `impl Texture` block
    (writeln!(dest, "impl {} {{", name)).unwrap();

    // writing the `new` function
    {
        let data_type = match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => "Texture1dData<P>",
            TextureDimensions::Texture2d | TextureDimensions::Texture2dArray => "Texture2dData<P>",
            TextureDimensions::Texture3d => "Texture3dData<P>",
        };

        let param = match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture2d |
            TextureDimensions::Texture3d => "T",

            TextureDimensions::Texture1dArray |
            TextureDimensions::Texture2dArray => "Vec<T>",
        };

        (writeln!(dest, "
                /// Builds a new texture by uploading data.
                ///
                /// This function will automatically generate all mipmaps of the texture.
                pub fn new<P: PixelValue, T: {data_type}>(display: &::Display, data: {param})
                    -> {name}
                {{
            ", data_type = data_type, param = param, name = name)).unwrap();

        // writing the `let format = ...` line
        match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture2d |
            TextureDimensions::Texture3d => {
                (writeln!(dest, "let format = data.get_format();")).unwrap();
            },
            TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => {
                (writeln!(dest, "let format = data[0].get_format();")).unwrap();
            },
        }
        match ty {
            TextureType::Compressed => {
                (write!(dest, "let format = format.to_default_compressed_format();")).unwrap();
            },
            TextureType::Regular | TextureType::Integral | TextureType::Unsigned => {
                (write!(dest, "let format = format.to_default_float_format();")).unwrap();
            },
        };

        // writing the `let (client_format, client_type) = ...` line
        match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture2d |
            TextureDimensions::Texture3d => {
                (writeln!(dest, "let client_format = data.get_format();")).unwrap();
            },
            TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => {
                (writeln!(dest, "let client_format = data[0].get_format();")).unwrap();
            },
        }
        (write!(dest, "let (client_format, client_type) = ")).unwrap();
        match ty {
            TextureType::Compressed | TextureType::Regular => {
                (write!(dest, "client_format.to_gl_enum()")).unwrap();
            },
            TextureType::Integral => {
                (write!(dest, "client_format.to_gl_enum_int().expect(\"Client format must \
                               have an integral format\")")).unwrap();
            },
            TextureType::Unsigned => {
                (write!(dest, "client_format.to_gl_enum_uint().expect(\"Client format must \
                               have an integral format\")")).unwrap();
            },
        };
        (writeln!(dest, ";")).unwrap();

        match dimensions {
            TextureDimensions::Texture1d => (write!(dest, "
                    let data = data.into_vec();
                    let width = data.len() as u32;
                ")).unwrap(),

            TextureDimensions::Texture2d => (write!(dest, "
                    let (width, height) = data.get_dimensions();
                    let width = width as u32; let height = height as u32;
                    let data = data.into_vec();
                ")).unwrap(),

            TextureDimensions::Texture3d => (write!(dest, "
                    let (width, height, depth) = data.get_dimensions();
                    let width = width as u32; let height = height as u32; let depth = depth as u32;
                    let data = data.into_vec();
                ")).unwrap(),

            TextureDimensions::Texture1dArray => (write!(dest, "
                    let array_size = data.len() as u32;
                    let mut width = 0;
                    let data = data.into_iter().flat_map(|t| {{
                        let d = t.into_vec(); width = d.len(); d.into_iter()
                    }}).collect();
                    let width = width as u32;
                ")).unwrap(),   // TODO: panic if dimensions are inconsistent

            TextureDimensions::Texture2dArray => (write!(dest, "
                    let array_size = data.len() as u32;
                    let mut dimensions = (0, 0);
                    let data = data.into_iter().flat_map(|t| {{
                        dimensions = t.get_dimensions(); t.into_vec().into_iter()
                    }}).collect();
                    let (width, height) = dimensions;
                    let width = width as u32; let height = height as u32;
                ")).unwrap(),   // TODO: panic if dimensions are inconsistent
        }
        // writing the constructor
        (write!(dest, "{}(TextureImplementation::new(display, format, Some(data), \
                       client_format, client_type, ", name)).unwrap();
        match dimensions {
            TextureDimensions::Texture1d => (write!(dest, "width, None, None, None")).unwrap(),
            TextureDimensions::Texture2d => (write!(dest, "width, Some(height), None, None")).unwrap(),
            TextureDimensions::Texture3d => (write!(dest, "width, Some(height), Some(depth), None")).unwrap(),
            TextureDimensions::Texture1dArray => (write!(dest, "width, None, None, Some(array_size)")).unwrap(),
            TextureDimensions::Texture2dArray => (write!(dest, "width, Some(height), None, Some(array_size)")).unwrap(),
        }
        (writeln!(dest, "))")).unwrap();

        // end of "new" function block
        (writeln!(dest, "}}")).unwrap();
    }

    // writing the `new_empty` function
    if ty != TextureType::Compressed {
        let format = match ty {
            TextureType::Regular => "UncompressedFloatFormat",
            TextureType::Compressed => "CompressedFormat",
            TextureType::Integral => "UncompressedIntFormat",
            TextureType::Unsigned => "UncompressedUintFormat",
        };

        let dim_params = match dimensions {
            TextureDimensions::Texture1d => "width: u32",
            TextureDimensions::Texture2d => "width: u32, height: u32",
            TextureDimensions::Texture3d => "width: u32, height: u32, depth: u32",
            TextureDimensions::Texture1dArray => "width: u32, array_size: u32",
            TextureDimensions::Texture2dArray => "width: u32, height: u32, array_size: u32",
        };

        // opening function
        (writeln!(dest, "
                /// Creates an empty texture.
                ///
                /// The texture will contain undefined data.
                pub fn new_empty(display: &::Display, format: {format}, {dim_params}) -> {name} {{
                    let format = format.to_gl_enum();
            ", format = format, dim_params = dim_params, name = name)).unwrap();

        // writing the constructor
        (write!(dest, "{}(TextureImplementation::new::<u8>(display, format, None, \
                       0, 0, ", name)).unwrap();
        match dimensions {
            TextureDimensions::Texture1d => (write!(dest, "width, None, None, None")).unwrap(),
            TextureDimensions::Texture2d => (write!(dest, "width, Some(height), None, None")).unwrap(),
            TextureDimensions::Texture3d => (write!(dest, "width, Some(height), Some(depth), None")).unwrap(),
            TextureDimensions::Texture1dArray => (write!(dest, "width, None, None, Some(array_size)")).unwrap(),
            TextureDimensions::Texture2dArray => (write!(dest, "width, Some(height), None, Some(array_size)")).unwrap(),
        }
        (writeln!(dest, "))")).unwrap();

        // closing function
        (writeln!(dest, "}}")).unwrap();
    }

    // writing the `as_surface` function
    if dimensions == TextureDimensions::Texture2d && ty == TextureType::Regular {
        (write!(dest, "
                /// Starts drawing on the texture.
                ///
                /// All the function calls to the `TextureSurface` will draw on the texture instead
                /// of the screen.
                ///
                /// ## Low-level informations
                ///
                /// The first time that this function is called, a FrameBuffer Object will be
                /// created and cached. The following calls to `as_surface` will load the existing
                /// FBO and re-use it. When the texture is destroyed, the FBO is destroyed too.
                ///
                pub fn as_surface<'a>(&'a self) -> TextureSurface<'a> {{
                    // TODO: hacky, shouldn't recreate a Display
                    TextureSurface(framebuffer::FrameBuffer::new(&::Display {{ context: self.0.display.clone() }})
                        .with_color_texture(self))
                }}
            ")).unwrap();
    }

    // writing the `read` function
    // TODO: implement for arrays too
    if dimensions != TextureDimensions::Texture1dArray && dimensions != TextureDimensions::Texture2dArray {
        let (data_type, constructor) = match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => (
                    "Texture1dData<P>",
                    "Texture1dData::from_vec(data)"
                ),
            TextureDimensions::Texture2d | TextureDimensions::Texture2dArray => (
                    "Texture2dData<P>",
                    "Texture2dData::from_vec(data, self.get_width() as u32)"
                ),
            TextureDimensions::Texture3d => (
                    "Texture3dData<P>",
                    "Texture3dData::from_vec(data, self.get_width() as u32, \
                                             self.get_height().unwrap() as u32)"
                ),
        };

        (write!(dest, r#"
                /// Reads the content of the texture.
                ///
                /// # Features
                ///
                /// This method is always only if the `gl_extensions` feature is enabled.
                #[cfg(feature = "gl_extensions")]
                pub fn read<P, T>(&self) -> T where P: PixelValue, T: {data_type} {{
                    let data = self.0.read::<P>(0);
                    {constructor}
                }}
            "#, data_type = data_type, constructor = constructor)).unwrap();
    }

    // closing `impl Texture` block
    (writeln!(dest, "}}")).unwrap();
}
<commit_msg>Fix new_empty triggering a GL error<commit_after>#[deriving(PartialEq, Eq)]
enum TextureType {
    Regular,
    Compressed,
    Integral,
    Unsigned,
}

#[deriving(PartialEq, Eq)]
enum TextureDimensions {
    Texture1d,
    Texture2d,
    Texture3d,
    Texture1dArray,
    Texture2dArray,
}

pub fn build_texture_file<W: Writer>(mut dest: &mut W) {
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture1d);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2d);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture3d);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture1dArray);
    build_texture(dest, TextureType::Regular, TextureDimensions::Texture2dArray);
    build_texture(dest, TextureType::Compressed, TextureDimensions::Texture2dArray);
    build_texture(dest, TextureType::Integral, TextureDimensions::Texture2dArray);
    build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2dArray);
}

fn build_texture<W: Writer>(mut dest: &mut W, ty: TextureType, dimensions: TextureDimensions) {
    // building the name of the texture type
    let name: String = {
        let prefix = match ty {
            TextureType::Regular => "",
            TextureType::Compressed => "Compressed",
            TextureType::Integral => "Integral",
            TextureType::Unsigned => "Unsigned",
        };

        let suffix = match dimensions {
            TextureDimensions::Texture1d => "Texture1d",
            TextureDimensions::Texture2d => "Texture2d",
            TextureDimensions::Texture3d => "Texture3d",
            TextureDimensions::Texture1dArray => "Texture1dArray",
            TextureDimensions::Texture2dArray => "Texture2dArray",
        };

        format!("{}{}", prefix, suffix)
    };

    // writing the struct with doc-comment
    (write!(dest, "/// ")).unwrap();
    (write!(dest, "{}", match dimensions {
        TextureDimensions::Texture1d | TextureDimensions::Texture2d |
        TextureDimensions::Texture3d => "A ",
        TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "An array of ",
    })).unwrap();
    if ty == TextureType::Compressed {
        (write!(dest, "compressed ")).unwrap();
    }
    (write!(dest, "{}", match dimensions {
        TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => "one-dimensional ",
        TextureDimensions::Texture2d | TextureDimensions::Texture2dArray => "two-dimensional ",
        TextureDimensions::Texture3d => "three-dimensional ",
    })).unwrap();
    (write!(dest, "{}", match dimensions {
        TextureDimensions::Texture1d | TextureDimensions::Texture2d |
        TextureDimensions::Texture3d => "texture ",
        TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "textures ",
    })).unwrap();
    (write!(dest, "{}", match ty {
        TextureType::Regular | TextureType::Compressed => " containing floating-point data",
        TextureType::Integral => " containing signed integral data",
        TextureType::Unsigned => " containing unsigned integral data",
    })).unwrap();
    (writeln!(dest, ".")).unwrap();
    (writeln!(dest, "pub struct {}(TextureImplementation);", name)).unwrap();

    // `Texture` trait impl
    (writeln!(dest, "
                impl Texture for {} {{
                    fn get_implementation(&self) -> &TextureImplementation {{
                        &self.0
                    }}
                }}
            ", name)).unwrap();

    // `UniformValue` trait impl
    (writeln!(dest, "
                impl<'a> UniformValue for &'a {} {{
                    fn to_binder(&self) -> UniformValueBinder {{
                        self.get_implementation().to_binder()
                    }}
                }}
            ", name)).unwrap();

    // opening `impl Texture` block
    (writeln!(dest, "impl {} {{", name)).unwrap();

    // writing the `new` function
    {
        let data_type = match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => "Texture1dData<P>",
            TextureDimensions::Texture2d | TextureDimensions::Texture2dArray => "Texture2dData<P>",
            TextureDimensions::Texture3d => "Texture3dData<P>",
        };

        let param = match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture2d |
            TextureDimensions::Texture3d => "T",

            TextureDimensions::Texture1dArray |
            TextureDimensions::Texture2dArray => "Vec<T>",
        };

        (writeln!(dest, "
                /// Builds a new texture by uploading data.
                ///
                /// This function will automatically generate all mipmaps of the texture.
                pub fn new<P: PixelValue, T: {data_type}>(display: &::Display, data: {param})
                    -> {name}
                {{
            ", data_type = data_type, param = param, name = name)).unwrap();

        // writing the `let format = ...` line
        match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture2d |
            TextureDimensions::Texture3d => {
                (writeln!(dest, "let format = data.get_format();")).unwrap();
            },
            TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => {
                (writeln!(dest, "let format = data[0].get_format();")).unwrap();
            },
        }
        match ty {
            TextureType::Compressed => {
                (write!(dest, "let format = format.to_default_compressed_format();")).unwrap();
            },
            TextureType::Regular | TextureType::Integral | TextureType::Unsigned => {
                (write!(dest, "let format = format.to_default_float_format();")).unwrap();
            },
        };

        // writing the `let (client_format, client_type) = ...` line
        match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture2d |
            TextureDimensions::Texture3d => {
                (writeln!(dest, "let client_format = data.get_format();")).unwrap();
            },
            TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => {
                (writeln!(dest, "let client_format = data[0].get_format();")).unwrap();
            },
        }
        (write!(dest, "let (client_format, client_type) = ")).unwrap();
        match ty {
            TextureType::Compressed | TextureType::Regular => {
                (write!(dest, "client_format.to_gl_enum()")).unwrap();
            },
            TextureType::Integral => {
                (write!(dest, "client_format.to_gl_enum_int().expect(\"Client format must \
                               have an integral format\")")).unwrap();
            },
            TextureType::Unsigned => {
                (write!(dest, "client_format.to_gl_enum_uint().expect(\"Client format must \
                               have an integral format\")")).unwrap();
            },
        };
        (writeln!(dest, ";")).unwrap();

        match dimensions {
            TextureDimensions::Texture1d => (write!(dest, "
                    let data = data.into_vec();
                    let width = data.len() as u32;
                ")).unwrap(),

            TextureDimensions::Texture2d => (write!(dest, "
                    let (width, height) = data.get_dimensions();
                    let width = width as u32; let height = height as u32;
                    let data = data.into_vec();
                ")).unwrap(),

            TextureDimensions::Texture3d => (write!(dest, "
                    let (width, height, depth) = data.get_dimensions();
                    let width = width as u32; let height = height as u32; let depth = depth as u32;
                    let data = data.into_vec();
                ")).unwrap(),

            TextureDimensions::Texture1dArray => (write!(dest, "
                    let array_size = data.len() as u32;
                    let mut width = 0;
                    let data = data.into_iter().flat_map(|t| {{
                        let d = t.into_vec(); width = d.len(); d.into_iter()
                    }}).collect();
                    let width = width as u32;
                ")).unwrap(),   // TODO: panic if dimensions are inconsistent

            TextureDimensions::Texture2dArray => (write!(dest, "
                    let array_size = data.len() as u32;
                    let mut dimensions = (0, 0);
                    let data = data.into_iter().flat_map(|t| {{
                        dimensions = t.get_dimensions(); t.into_vec().into_iter()
                    }}).collect();
                    let (width, height) = dimensions;
                    let width = width as u32; let height = height as u32;
                ")).unwrap(),   // TODO: panic if dimensions are inconsistent
        }
        // writing the constructor
        (write!(dest, "{}(TextureImplementation::new(display, format, Some(data), \
                       client_format, client_type, ", name)).unwrap();
        match dimensions {
            TextureDimensions::Texture1d => (write!(dest, "width, None, None, None")).unwrap(),
            TextureDimensions::Texture2d => (write!(dest, "width, Some(height), None, None")).unwrap(),
            TextureDimensions::Texture3d => (write!(dest, "width, Some(height), Some(depth), None")).unwrap(),
            TextureDimensions::Texture1dArray => (write!(dest, "width, None, None, Some(array_size)")).unwrap(),
            TextureDimensions::Texture2dArray => (write!(dest, "width, Some(height), None, Some(array_size)")).unwrap(),
        }
        (writeln!(dest, "))")).unwrap();

        // end of "new" function block
        (writeln!(dest, "}}")).unwrap();
    }

    // writing the `new_empty` function
    if ty != TextureType::Compressed {
        let format = match ty {
            TextureType::Regular => "UncompressedFloatFormat",
            TextureType::Compressed => "CompressedFormat",
            TextureType::Integral => "UncompressedIntFormat",
            TextureType::Unsigned => "UncompressedUintFormat",
        };

        let dim_params = match dimensions {
            TextureDimensions::Texture1d => "width: u32",
            TextureDimensions::Texture2d => "width: u32, height: u32",
            TextureDimensions::Texture3d => "width: u32, height: u32, depth: u32",
            TextureDimensions::Texture1dArray => "width: u32, array_size: u32",
            TextureDimensions::Texture2dArray => "width: u32, height: u32, array_size: u32",
        };

        // opening function
        (writeln!(dest, "
                /// Creates an empty texture.
                ///
                /// The texture will contain undefined data.
                pub fn new_empty(display: &::Display, format: {format}, {dim_params}) -> {name} {{
                    let format = format.to_gl_enum();
            ", format = format, dim_params = dim_params, name = name)).unwrap();

        // writing the constructor
        (write!(dest, "{}(TextureImplementation::new::<u8>(display, format, None, \
                       gl::RGBA, gl::UNSIGNED_BYTE, ", name)).unwrap();
        match dimensions {
            TextureDimensions::Texture1d => (write!(dest, "width, None, None, None")).unwrap(),
            TextureDimensions::Texture2d => (write!(dest, "width, Some(height), None, None")).unwrap(),
            TextureDimensions::Texture3d => (write!(dest, "width, Some(height), Some(depth), None")).unwrap(),
            TextureDimensions::Texture1dArray => (write!(dest, "width, None, None, Some(array_size)")).unwrap(),
            TextureDimensions::Texture2dArray => (write!(dest, "width, Some(height), None, Some(array_size)")).unwrap(),
        }
        (writeln!(dest, "))")).unwrap();

        // closing function
        (writeln!(dest, "}}")).unwrap();
    }

    // writing the `as_surface` function
    if dimensions == TextureDimensions::Texture2d && ty == TextureType::Regular {
        (write!(dest, "
                /// Starts drawing on the texture.
                ///
                /// All the function calls to the `TextureSurface` will draw on the texture instead
                /// of the screen.
                ///
                /// ## Low-level informations
                ///
                /// The first time that this function is called, a FrameBuffer Object will be
                /// created and cached. The following calls to `as_surface` will load the existing
                /// FBO and re-use it. When the texture is destroyed, the FBO is destroyed too.
                ///
                pub fn as_surface<'a>(&'a self) -> TextureSurface<'a> {{
                    // TODO: hacky, shouldn't recreate a Display
                    TextureSurface(framebuffer::FrameBuffer::new(&::Display {{ context: self.0.display.clone() }})
                        .with_color_texture(self))
                }}
            ")).unwrap();
    }

    // writing the `read` function
    // TODO: implement for arrays too
    if dimensions != TextureDimensions::Texture1dArray && dimensions != TextureDimensions::Texture2dArray {
        let (data_type, constructor) = match dimensions {
            TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => (
                    "Texture1dData<P>",
                    "Texture1dData::from_vec(data)"
                ),
            TextureDimensions::Texture2d | TextureDimensions::Texture2dArray => (
                    "Texture2dData<P>",
                    "Texture2dData::from_vec(data, self.get_width() as u32)"
                ),
            TextureDimensions::Texture3d => (
                    "Texture3dData<P>",
                    "Texture3dData::from_vec(data, self.get_width() as u32, \
                                             self.get_height().unwrap() as u32)"
                ),
        };

        (write!(dest, r#"
                /// Reads the content of the texture.
                ///
                /// # Features
                ///
                /// This method is always only if the `gl_extensions` feature is enabled.
                #[cfg(feature = "gl_extensions")]
                pub fn read<P, T>(&self) -> T where P: PixelValue, T: {data_type} {{
                    let data = self.0.read::<P>(0);
                    {constructor}
                }}
            "#, data_type = data_type, constructor = constructor)).unwrap();
    }

    // closing `impl Texture` block
    (writeln!(dest, "}}")).unwrap();
}
<|endoftext|>


<commit_before>extern crate image;
extern crate bspline;

use std::ops::{Mul, Add};
use std::iter;

#[derive(Copy, Clone, Debug)]
struct Point {
    x: f32,
    y: f32,
}
impl Point {
    fn new(x: f32, y: f32) -> Point {
        Point { x: x, y: y }
    }
}
impl Mul<f32> for Point {
    type Output = Point;
    fn mul(self, rhs: f32) -> Point {
        Point { x: self.x * rhs, y: self.y * rhs }
    }
}
impl Add for Point {
    type Output = Point;
    fn add(self, rhs: Point) -> Point {
        Point { x: self.x + rhs.x, y: self.y + rhs.y }
    }
}

/// Evaluate the B-spline and plot it to the image buffer passed
fn plot_2d(spline: &bspline::BSpline<Point>, plot: &mut [u8], plot_dim: (usize, usize), scale: (f32, f32),
           offset: (f32, f32), t_range: (f32, f32)) {
    let step_size = 0.001;
    let steps = ((t_range.1 - t_range.0) / step_size) as usize;
    for s in 0..steps {
        let t = step_size * s as f32 + t_range.0;
        let pt = spline.point(t);
        let ix = ((pt.x + offset.0) * scale.0) as isize;
        let iy = ((pt.y + offset.1) * scale.1) as isize;
        for y in iy - 1..iy + 1 {
            for x in ix - 1..ix + 1 {
                if y >= 0 && y < plot_dim.1 as isize && x >= 0 && x < plot_dim.0 as isize {
                    let px = (plot_dim.1 - 1 - y as usize) * plot_dim.0 * 3 + x as usize * 3;
                    for i in 0..3 {
                        plot[px + i] = 0;
                    }
                }
            }
        }
    }
    // Draw the control points
    for pt in spline.control_points() {
        let ix = ((pt.x + offset.0) * scale.0) as isize;
        let iy = ((pt.y + offset.1) * scale.1) as isize;
        // Plot a 4x4 red marker for each control point
        for y in iy - 3..iy + 3 {
            for x in ix - 3..ix + 3 {
                if y >= 0 && y < plot_dim.1 as isize && x >= 0 && x < plot_dim.0 as isize {
                    let px = (plot_dim.1 - 1 - y as usize) * plot_dim.0 * 3 + x as usize * 3;
                    plot[px] = 255;
                    plot[px + 1] = 0;
                    plot[px + 2] = 0;
                }
            }
        }
    }
}

/// Plot a simple 2D quadratic B-spline
fn plot_quadratic() {
    let points = vec![Point::new(-1.5, 0.0), Point::new(-1.0, 1.5), Point::new(0.0, -1.0),
                      Point::new(1.0, 0.0), Point::new(0.75, -1.6)];
    let knots = vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0];
    let t_start = knots[0];
    let t_end = knots[knots.len() - 1];

    let plot_dim = (720, 540);
    let scale = (plot_dim.0 as f32 / 4.0, plot_dim.1 as f32 / 4.0);
    let offset = (2.0, 2.0);

    let mut plot: Vec<_> = iter::repeat(255u8).take(plot_dim.0 * plot_dim.1 * 3).collect();

    println!("Plotting Quadratic B-spline with:\n\tpoints = {:?}\n\tknots = {:?}",
             points, knots);
    println!("\tStarting at {}, ending at {}", t_start, t_end);
    let spline = bspline::BSpline::new(2, points, knots);

    plot_2d(&spline, &mut plot[..], plot_dim, scale, offset, (t_start, t_end));
    match image::save_buffer("quadratic_2d.png", &plot[..], plot_dim.0 as u32, plot_dim.1 as u32, image::RGB(8)) {
        Ok(_) => println!("2D Quadratic B-spline saved to quadratic_2d.png"),
        Err(e) => println!("Error saving quadratic_2d.png,  {}", e),
    }
}
/// Plot a simple 2D cubic B-spline
fn plot_cubic() {
    let points = vec![Point::new(-1.5, 1.2), Point::new(-1.8, 0.5), Point::new(-0.7, -0.25),
                      Point::new(0.0, 1.8), Point::new(0.9, 0.2), Point::new(0.3, -0.6),
                      Point::new(1.5, -0.5)];
    let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
    let t_start = knots[0];
    let t_end = knots[knots.len() - 1];

    let plot_dim = (720, 540);
    let scale = (plot_dim.0 as f32 / 4.0, plot_dim.1 as f32 / 4.0);
    let offset = (2.0, 2.0);

    let mut plot: Vec<_> = iter::repeat(255u8).take(plot_dim.0 * plot_dim.1 * 3).collect();

    println!("Plotting Cubic B-spline with:\n\tpoints = {:?}\n\tknots = {:?}",
             points, knots);
    println!("\tStarting at {}, ending at {}", t_start, t_end);
    let spline = bspline::BSpline::new(3, points, knots);

    plot_2d(&spline, &mut plot[..], plot_dim, scale, offset, (t_start, t_end));
    match image::save_buffer("cubic_2d.png", &plot[..], plot_dim.0 as u32, plot_dim.1 as u32, image::RGB(8)) {
        Ok(_) => println!("2D Cubic B-spline saved to cubic_2d.png"),
        Err(e) => println!("Error saving cubic_2d.png,  {}", e),
    }
}
/// Plot a simple 2D quartic B-spline
fn plot_quartic() {
        let points = vec![Point::new(-1.8, -1.4), Point::new(-1.2, 0.5), Point::new(-0.2, -0.8),
                          Point::new(-0.6, 0.7), Point::new(0.0, 1.6), Point::new(1.0, 0.0),
                          Point::new(0.6, -0.3), Point::new(0.6, -0.3), Point::new(0.0, -1.0)];
        let knots = vec![0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0];
    let t_start = knots[0];
    let t_end = knots[knots.len() - 1];

    let plot_dim = (720, 540);
    let scale = (plot_dim.0 as f32 / 4.0, plot_dim.1 as f32 / 4.0);
    let offset = (2.0, 2.0);

    let mut plot: Vec<_> = iter::repeat(255u8).take(plot_dim.0 * plot_dim.1 * 3).collect();

    println!("Plotting Quartic B-spline with:\n\tpoints = {:?}\n\tknots = {:?}",
             points, knots);
    println!("\tStarting at {}, ending at {}", t_start, t_end);
    let spline = bspline::BSpline::new(4, points, knots);

    plot_2d(&spline, &mut plot[..], plot_dim, scale, offset, (t_start, t_end));
    match image::save_buffer("quartic_2d.png", &plot[..], plot_dim.0 as u32, plot_dim.1 as u32, image::RGB(8)) {
        Ok(_) => println!("2D Quartic B-spline saved to quartic_2d.png"),
        Err(e) => println!("Error saving quartic_2d.png,  {}", e),
    }
}

fn main() {
    let divider: String = iter::repeat('-').take(80).collect();
    plot_quadratic();
    println!("{}\n\n{}", divider, divider);
    plot_cubic();
    println!("{}\n\n{}", divider, divider);
    plot_quartic();
}

<commit_msg>Improve 2D examples<commit_after>extern crate image;
extern crate bspline;

use std::ops::{Mul, Add};
use std::iter;

#[derive(Copy, Clone, Debug)]
struct Point {
    x: f32,
    y: f32,
}
impl Point {
    fn new(x: f32, y: f32) -> Point {
        Point { x: x, y: y }
    }
}
impl Mul<f32> for Point {
    type Output = Point;
    fn mul(self, rhs: f32) -> Point {
        Point { x: self.x * rhs, y: self.y * rhs }
    }
}
impl Add for Point {
    type Output = Point;
    fn add(self, rhs: Point) -> Point {
        Point { x: self.x + rhs.x, y: self.y + rhs.y }
    }
}

/// Evaluate the B-spline and plot it to the image buffer passed
fn plot_2d(spline: &bspline::BSpline<Point>, plot: &mut [u8], plot_dim: (usize, usize), scale: (f32, f32),
           offset: (f32, f32), t_range: (f32, f32)) {
    let step_size = 0.001;
    let steps = ((t_range.1 - t_range.0) / step_size) as usize;
    for s in 0..steps {
        let t = step_size * s as f32 + t_range.0;
        let pt = spline.point(t);
        let ix = ((pt.x + offset.0) * scale.0) as isize;
        let iy = ((pt.y + offset.1) * scale.1) as isize;
        for y in iy - 1..iy + 1 {
            for x in ix - 1..ix + 1 {
                if y >= 0 && y < plot_dim.1 as isize && x >= 0 && x < plot_dim.0 as isize {
                    let px = (plot_dim.1 - 1 - y as usize) * plot_dim.0 * 3 + x as usize * 3;
                    for i in 0..3 {
                        plot[px + i] = 0;
                    }
                }
            }
        }
    }
    // Draw the control points
    for pt in spline.control_points() {
        let ix = ((pt.x + offset.0) * scale.0) as isize;
        let iy = ((pt.y + offset.1) * scale.1) as isize;
        // Plot a 4x4 red marker for each control point
        for y in iy - 3..iy + 3 {
            for x in ix - 3..ix + 3 {
                if y >= 0 && y < plot_dim.1 as isize && x >= 0 && x < plot_dim.0 as isize {
                    let px = (plot_dim.1 - 1 - y as usize) * plot_dim.0 * 3 + x as usize * 3;
                    plot[px] = 255;
                    plot[px + 1] = 0;
                    plot[px + 2] = 0;
                }
            }
        }
    }
}

fn plot_test() {
    let points = vec![Point::new(-2.5, 1.5), Point::new(-2.0, -1.5),
                      Point::new(-1.5, 1.5), Point::new(-1.0, -1.5),
                      Point::new(-0.5, 1.5), Point::new(0.0, -1.5),
                      Point::new(0.5, 1.5), Point::new(1.0, -1.5),
                      Point::new(1.5, 1.5), Point::new(2.0, -1.5),
                      Point::new(2.5, 1.5)];
    let knots = vec![0.0, 0.0, 0.0, 0.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0,
                     10.0, 11.0, 12.0, 13.0, 14.0];
    let degree = 3;
    let t_start = knots[degree];
    let t_end = knots[knots.len() - 1 - degree];

    let plot_dim = (720, 540);
    let scale = (plot_dim.0 as f32 / 6.0, plot_dim.1 as f32 / 4.0);
    let offset = (3.0, 2.0);

    let mut plot: Vec<_> = iter::repeat(255u8).take(plot_dim.0 * plot_dim.1 * 3).collect();

    println!("Plotting B-spline with:\n\tpoints = {:?}\n\tknots = {:?}",
             points, knots);
    println!("\tStarting at {}, ending at {}", t_start, t_end);
    let spline = bspline::BSpline::new(degree, points, knots);

    plot_2d(&spline, &mut plot[..], plot_dim, scale, offset, (t_start, t_end));
    match image::save_buffer("test.png", &plot[..], plot_dim.0 as u32, plot_dim.1 as u32, image::RGB(8)) {
        Ok(_) => println!("Test B-spline saved to test.png"),
        Err(e) => println!("Error saving test.png,  {}", e),
    }
}

/// Plot a simple 2D quadratic B-spline
fn plot_quadratic() {
    let points = vec![Point::new(-1.5, 0.0), Point::new(0.0, 1.5), Point::new(1.5, 0.0)];
    let knots = vec![0.0, 0.0, 0.0, 3.0, 3.0, 3.0];
    let degree = 2;
    let t_start = knots[degree];
    let t_end = knots[knots.len() - 1 - degree];

    let plot_dim = (720, 540);
    let scale = (plot_dim.0 as f32 / 4.0, plot_dim.1 as f32 / 4.0);
    let offset = (2.0, 2.0);

    let mut plot: Vec<_> = iter::repeat(255u8).take(plot_dim.0 * plot_dim.1 * 3).collect();

    println!("Plotting Quadratic B-spline with:\n\tpoints = {:?}\n\tknots = {:?}",
             points, knots);
    println!("\tStarting at {}, ending at {}", t_start, t_end);
    let spline = bspline::BSpline::new(degree, points, knots);

    plot_2d(&spline, &mut plot[..], plot_dim, scale, offset, (t_start, t_end));
    match image::save_buffer("quadratic_2d.png", &plot[..], plot_dim.0 as u32, plot_dim.1 as u32, image::RGB(8)) {
        Ok(_) => println!("2D Quadratic B-spline saved to quadratic_2d.png"),
        Err(e) => println!("Error saving quadratic_2d.png,  {}", e),
    }
}
/// Plot a simple 2D cubic B-spline
fn plot_cubic() {
    let points = vec![Point::new(-1.5, -1.5), Point::new(-0.5, 1.5),
                      Point::new(0.5, -1.5), Point::new(1.5, 1.5)];
    let knots = vec![0.0, 1.0, 2.0, 2.0, 5.0, 5.0, 6.0, 7.0];
    let degree = 3;
    let t_start = knots[degree];
    let t_end = knots[knots.len() - 1 - degree];

    let plot_dim = (720, 540);
    let scale = (plot_dim.0 as f32 / 4.0, plot_dim.1 as f32 / 4.0);
    let offset = (2.0, 2.0);

    let mut plot: Vec<_> = iter::repeat(255u8).take(plot_dim.0 * plot_dim.1 * 3).collect();

    println!("Plotting Cubic B-spline with:\n\tpoints = {:?}\n\tknots = {:?}",
             points, knots);
    println!("\tStarting at {}, ending at {}", t_start, t_end);
    let spline = bspline::BSpline::new(degree, points, knots);

    plot_2d(&spline, &mut plot[..], plot_dim, scale, offset, (t_start, t_end));
    match image::save_buffer("cubic_2d.png", &plot[..], plot_dim.0 as u32, plot_dim.1 as u32, image::RGB(8)) {
        Ok(_) => println!("2D Cubic B-spline saved to cubic_2d.png"),
        Err(e) => println!("Error saving cubic_2d.png,  {}", e),
    }
}
/// Plot a simple 2D quartic B-spline
fn plot_quartic() {
    let points = vec![Point::new(-1.8, -1.4), Point::new(-1.2, 0.5), Point::new(-0.2, -0.8),
                      Point::new(-0.6, 0.7), Point::new(0.0, 1.6), Point::new(1.0, 0.0),
                      Point::new(0.6, -0.3), Point::new(0.0, -1.0)];
    let knots = vec![0.0, 0.0, 0.0, 0.0, 0.2, 1.0, 2.0, 3.0, 5.0, 5.0, 5.0, 5.0, 5.0];
    let degree = 4;
    let t_start = knots[degree];
    let t_end = knots[knots.len() - 1 - degree];

    let plot_dim = (720, 540);
    let scale = (plot_dim.0 as f32 / 4.0, plot_dim.1 as f32 / 4.0);
    let offset = (2.0, 2.0);

    let mut plot: Vec<_> = iter::repeat(255u8).take(plot_dim.0 * plot_dim.1 * 3).collect();

    println!("Plotting Quartic B-spline with:\n\tpoints = {:?}\n\tknots = {:?}",
             points, knots);
    println!("\tStarting at {}, ending at {}", t_start, t_end);
    let spline = bspline::BSpline::new(degree, points, knots);

    plot_2d(&spline, &mut plot[..], plot_dim, scale, offset, (t_start, t_end));
    match image::save_buffer("quartic_2d.png", &plot[..], plot_dim.0 as u32, plot_dim.1 as u32, image::RGB(8)) {
        Ok(_) => println!("2D Quartic B-spline saved to quartic_2d.png"),
        Err(e) => println!("Error saving quartic_2d.png,  {}", e),
    }
}

fn main() {
    plot_test();
    let divider: String = iter::repeat('-').take(80).collect();
    plot_quadratic();
    println!("{}\n\n{}", divider, divider);
    plot_cubic();
    println!("{}\n\n{}", divider, divider);
    plot_quartic();
}

<|endoftext|>


<commit_before>#[cfg(feature = "script_helper")]
fn main() -> Result<(), Box<dyn Error>> {
    use handlebars::Handlebars;
    use std::error::Error;
    #[macro_use]
    extern crate serde_json;

    let mut handlebars = Handlebars::new();

    handlebars.register_template_file("tpl", "./examples/script/template.hbs")?;
    handlebars.register_script_helper_file("score", "./examples/script/goals.rhai")?;

    let data = json! {[
        [{
            "name": "Dortmund",
            "goals": ["Haaland", "Guerreiro", "Hazard", "Guerreiro"]
        }, {
            "name": "Schalke",
            "goals": []
        }],
        [{
            "name": "RB Leipzig",
            "goals": ["Poulsen"]
        }, {
            "name": "SC Feriburg",
            "goals": ["Gulde"]
        }]
    ]};
    println!("{}", handlebars.render("tpl", &data)?);
    Ok(())
}

#[cfg(not(feature = "script_helper"))]
fn main() {
    println!("Please enable feature flag script_helper for this example");
}
<commit_msg>(fix) import in script_helper example<commit_after>use std::error::Error;

#[cfg(feature = "script_helper")]
fn main() -> Result<(), Box<dyn Error>> {
    use handlebars::Handlebars;
    #[macro_use]
    extern crate serde_json;

    let mut handlebars = Handlebars::new();

    handlebars.register_template_file("tpl", "./examples/script/template.hbs")?;
    handlebars.register_script_helper_file("score", "./examples/script/goals.rhai")?;

    let data = json! {[
        [{
            "name": "Dortmund",
            "goals": ["Haaland", "Guerreiro", "Hazard", "Guerreiro"]
        }, {
            "name": "Schalke",
            "goals": []
        }],
        [{
            "name": "RB Leipzig",
            "goals": ["Poulsen"]
        }, {
            "name": "SC Feriburg",
            "goals": ["Gulde"]
        }]
    ]};
    println!("{}", handlebars.render("tpl", &data)?);
    Ok(())
}

#[cfg(not(feature = "script_helper"))]
fn main() -> Result<(), Box<dyn Error>> {
    println!("Please enable feature flag script_helper for this example");
    Ok(())
}
<|endoftext|>


<commit_before>//! Run tests concurrently.
//!
//! This module provides the `ConcurrentRunner` struct which uses a pool of threads to run tests
//! concurrently.

use std::panic::catch_unwind;
use std::path::{Path, PathBuf};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use num_cpus;
use filetest::{TestResult, runone};

// Request sent to worker threads contains jobid and path.
struct Request(usize, PathBuf);

/// Reply from worker thread,
pub enum Reply {
    Starting { jobid: usize, thread_num: usize },
    Done { jobid: usize, result: TestResult },
    Tick,
}

/// Manage threads that run test jobs concurrently.
pub struct ConcurrentRunner {
    // Channel for sending requests to the worker threads.
    // The workers are sharing the receiver with an `Arc<Mutex<Receiver>>`.
    // This is `None` when shutting down.
    request_tx: Option<Sender<Request>>,

    // Channel for receiving replies from the workers.
    // Workers have their own `Sender`.
    reply_rx: Receiver<Reply>,

    handles: Vec<thread::JoinHandle<()>>,
}

impl ConcurrentRunner {
    /// Create a new `ConcurrentRunner` with threads spun up.
    pub fn new() -> ConcurrentRunner {
        let (request_tx, request_rx) = channel();
        let request_mutex = Arc::new(Mutex::new(request_rx));
        let (reply_tx, reply_rx) = channel();

        heartbeat_thread(reply_tx.clone());

        let handles = (0..num_cpus::get())
            .map(|num| worker_thread(num, request_mutex.clone(), reply_tx.clone()))
            .collect();

        ConcurrentRunner {
            request_tx: Some(request_tx),
            reply_rx: reply_rx,
            handles: handles,
        }
    }

    /// Shut down worker threads orderly. They will finish any queued jobs first.
    pub fn shutdown(&mut self) {
        self.request_tx = None;
    }

    /// Join all the worker threads.
    pub fn join(&mut self) {
        assert!(self.request_tx.is_none(), "must shutdown before join");
        for h in self.handles.drain(..) {
            if let Err(e) = h.join() {
                println!("worker panicked: {:?}", e);
            }
        }
    }

    /// Add a new job to the queues.
    pub fn put(&mut self, jobid: usize, path: &Path) {
        self.request_tx
            .as_ref()
            .expect("cannot push after shutdown")
            .send(Request(jobid, path.to_owned()))
            .expect("all the worker threads are gone");
    }

    /// Get a job reply without blocking.
    pub fn try_get(&mut self) -> Option<Reply> {
        self.reply_rx.try_recv().ok()
    }

    /// Get a job reply, blocking until one is available.
    pub fn get(&mut self) -> Option<Reply> {
        self.reply_rx.recv().ok()
    }
}

/// Spawn a heartbeat thread which sends ticks down the reply channel every second.
/// This lets us implement timeouts without the not yet stable `recv_timeout`.
fn heartbeat_thread(replies: Sender<Reply>) -> thread::JoinHandle<()> {
    thread::Builder::new()
        .name("heartbeat".to_string())
        .spawn(move || {
            while replies.send(Reply::Tick).is_ok() {
                thread::sleep(Duration::from_secs(1));
            }
        })
        .unwrap()
}

/// Spawn a worker thread running tests.
fn worker_thread(thread_num: usize,
                 requests: Arc<Mutex<Receiver<Request>>>,
                 replies: Sender<Reply>)
                 -> thread::JoinHandle<()> {
    thread::Builder::new()
        .name(format!("worker #{}", thread_num))
        .spawn(move || {
            loop {
                // Lock the mutex only long enough to extract a request.
                let Request(jobid, path) = match requests.lock().unwrap().recv() {
                    Err(..) => break, // TX end shuit down. exit thread.
                    Ok(req) => req,
                };

                // Tell them we're starting this job.
                // The receiver should always be present for this as long as we have jobs.
                replies.send(Reply::Starting {
                        jobid: jobid,
                        thread_num: thread_num,
                    })
                    .unwrap();

                let result = match catch_unwind(|| runone::run(path.as_path())) {
                    Ok(r) => r,
                    Err(e) => {
                        // The test panicked, leaving us a `Box<Any>`.
                        // Panics are usually strings.
                        if let Some(msg) = e.downcast_ref::<String>() {
                            Err(format!("panicked in worker #{}: {}", thread_num, msg))
                        } else if let Some(msg) = e.downcast_ref::<&'static str>() {
                            Err(format!("panicked in worker #{}: {}", thread_num, msg))
                        } else {
                            Err(format!("panicked in worker #{}", thread_num))
                        }
                    }
                };

                replies.send(Reply::Done {
                        jobid: jobid,
                        result: result,
                    })
                    .unwrap();
            }
        })
        .unwrap()
}
<commit_msg>Simplify with unwrap_or_else().<commit_after>//! Run tests concurrently.
//!
//! This module provides the `ConcurrentRunner` struct which uses a pool of threads to run tests
//! concurrently.

use std::panic::catch_unwind;
use std::path::{Path, PathBuf};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use num_cpus;
use filetest::{TestResult, runone};

// Request sent to worker threads contains jobid and path.
struct Request(usize, PathBuf);

/// Reply from worker thread,
pub enum Reply {
    Starting { jobid: usize, thread_num: usize },
    Done { jobid: usize, result: TestResult },
    Tick,
}

/// Manage threads that run test jobs concurrently.
pub struct ConcurrentRunner {
    // Channel for sending requests to the worker threads.
    // The workers are sharing the receiver with an `Arc<Mutex<Receiver>>`.
    // This is `None` when shutting down.
    request_tx: Option<Sender<Request>>,

    // Channel for receiving replies from the workers.
    // Workers have their own `Sender`.
    reply_rx: Receiver<Reply>,

    handles: Vec<thread::JoinHandle<()>>,
}

impl ConcurrentRunner {
    /// Create a new `ConcurrentRunner` with threads spun up.
    pub fn new() -> ConcurrentRunner {
        let (request_tx, request_rx) = channel();
        let request_mutex = Arc::new(Mutex::new(request_rx));
        let (reply_tx, reply_rx) = channel();

        heartbeat_thread(reply_tx.clone());

        let handles = (0..num_cpus::get())
            .map(|num| worker_thread(num, request_mutex.clone(), reply_tx.clone()))
            .collect();

        ConcurrentRunner {
            request_tx: Some(request_tx),
            reply_rx: reply_rx,
            handles: handles,
        }
    }

    /// Shut down worker threads orderly. They will finish any queued jobs first.
    pub fn shutdown(&mut self) {
        self.request_tx = None;
    }

    /// Join all the worker threads.
    pub fn join(&mut self) {
        assert!(self.request_tx.is_none(), "must shutdown before join");
        for h in self.handles.drain(..) {
            if let Err(e) = h.join() {
                println!("worker panicked: {:?}", e);
            }
        }
    }

    /// Add a new job to the queues.
    pub fn put(&mut self, jobid: usize, path: &Path) {
        self.request_tx
            .as_ref()
            .expect("cannot push after shutdown")
            .send(Request(jobid, path.to_owned()))
            .expect("all the worker threads are gone");
    }

    /// Get a job reply without blocking.
    pub fn try_get(&mut self) -> Option<Reply> {
        self.reply_rx.try_recv().ok()
    }

    /// Get a job reply, blocking until one is available.
    pub fn get(&mut self) -> Option<Reply> {
        self.reply_rx.recv().ok()
    }
}

/// Spawn a heartbeat thread which sends ticks down the reply channel every second.
/// This lets us implement timeouts without the not yet stable `recv_timeout`.
fn heartbeat_thread(replies: Sender<Reply>) -> thread::JoinHandle<()> {
    thread::Builder::new()
        .name("heartbeat".to_string())
        .spawn(move || {
            while replies.send(Reply::Tick).is_ok() {
                thread::sleep(Duration::from_secs(1));
            }
        })
        .unwrap()
}

/// Spawn a worker thread running tests.
fn worker_thread(thread_num: usize,
                 requests: Arc<Mutex<Receiver<Request>>>,
                 replies: Sender<Reply>)
                 -> thread::JoinHandle<()> {
    thread::Builder::new()
        .name(format!("worker #{}", thread_num))
        .spawn(move || {
            loop {
                // Lock the mutex only long enough to extract a request.
                let Request(jobid, path) = match requests.lock().unwrap().recv() {
                    Err(..) => break, // TX end shuit down. exit thread.
                    Ok(req) => req,
                };

                // Tell them we're starting this job.
                // The receiver should always be present for this as long as we have jobs.
                replies.send(Reply::Starting {
                        jobid: jobid,
                        thread_num: thread_num,
                    })
                    .unwrap();

                let result = catch_unwind(|| runone::run(path.as_path())).unwrap_or_else(|e| {
                    // The test panicked, leaving us a `Box<Any>`.
                    // Panics are usually strings.
                    if let Some(msg) = e.downcast_ref::<String>() {
                        Err(format!("panicked in worker #{}: {}", thread_num, msg))
                    } else if let Some(msg) = e.downcast_ref::<&'static str>() {
                        Err(format!("panicked in worker #{}: {}", thread_num, msg))
                    } else {
                        Err(format!("panicked in worker #{}", thread_num))
                    }
                });

                replies.send(Reply::Done {
                        jobid: jobid,
                        result: result,
                    })
                    .unwrap();
            }
        })
        .unwrap()
}
<|endoftext|>


<commit_before>use std::panic;

pub fn install_sigpipe_hook() {
    let hook = panic::take_hook();
    panic::set_hook(Box::new(move |info| {
        if let Some(res) = info.payload().downcast_ref::<String>() {
            if res.contains("Broken pipe") {
                return;
            }
        }
        hook(info)
    }));
}
<commit_msg>change ~ improve naming and documentation of default SIGPIPE handling<commit_after>// spell-checker:ignore () SIGPIPE maint uutils

use std::panic;

//## SIGPIPE handling background/discussions ...
//* `uutils` ~ <https://github.com/uutils/coreutils/issues/374> , <https://github.com/uutils/coreutils/pull/1106>
//* rust and `rg` ~ <https://github.com/rust-lang/rust/issues/62569> , <https://github.com/BurntSushi/ripgrep/issues/200> , <https://github.com/crev-dev/cargo-crev/issues/287>

pub fn mute_sigpipe_panic() {
    let hook = panic::take_hook();
    panic::set_hook(Box::new(move |info| {
        if let Some(res) = info.payload().downcast_ref::<String>() {
            if res.contains("Broken pipe") {
                return;
            }
        }
        hook(info)
    }));
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate futures;
extern crate futures_channel;
extern crate test;

use futures::task::{self, Wake, Waker};
use futures::executor::LocalPool;
use futures::prelude::*;

use futures_channel::mpsc::unbounded;
use futures_channel::mpsc::channel;
use futures_channel::mpsc::Sender;
use futures_channel::mpsc::UnboundedSender;

use test::Bencher;

fn notify_noop() -> Waker {
    struct Noop;

    impl Wake for Noop {
        fn wake(&self) {}
    }

    const NOOP : &'static Noop = &Noop;

    Waker::from(NOOP)
}

/// Single producer, single consumer
#[bench]
fn unbounded_1_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, mut rx) = unbounded();
        let pool = LocalPool::new();
        let mut exec = pool.executor();
        let waker = notify_noop();
        let mut map = task::LocalMap::new();
        let mut cx = task::Context::new(&mut map, &waker, &mut exec);

        // 1000 iterations to avoid measuring overhead of initialization
        // Result should be divided by 1000
        for i in 0..1000 {

            // Poll, not ready, park
            assert_eq!(Ok(Async::Pending), rx.poll(&mut cx));

            UnboundedSender::unbounded_send(&tx, i).unwrap();

            // Now poll ready
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll(&mut cx));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn unbounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, mut rx) = unbounded();
        let pool = LocalPool::new();
        let mut exec = pool.executor();
        let waker = notify_noop();
        let mut map = task::LocalMap::new();
        let mut cx = task::Context::new(&mut map, &waker, &mut exec);

        let tx: Vec<_> = (0..100).map(|_| tx.clone()).collect();

        // 1000 send/recv operations total, result should be divided by 1000
        for _ in 0..10 {
            for i in 0..tx.len() {
                assert_eq!(Ok(Async::Pending), rx.poll(&mut cx));

                UnboundedSender::unbounded_send(&tx[i], i).unwrap();

                assert_eq!(Ok(Async::Ready(Some(i))), rx.poll(&mut cx));
            }
        }
    })
}

#[bench]
fn unbounded_uncontended(b: &mut Bencher) {
    let pool = LocalPool::new();
    let mut exec = pool.executor();
    let waker = notify_noop();
    let mut map = task::LocalMap::new();
    let mut cx = task::Context::new(&mut map, &waker, &mut exec);

    b.iter(|| {
        let (tx, mut rx) = unbounded();

        for i in 0..1000 {
            UnboundedSender::unbounded_send(&tx, i).expect("send");
            // No need to create a task, because poll is not going to park.
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll(&mut cx));
        }
    })
}

/// A Stream that continuously sends incrementing number of the queue
struct TestSender {
    tx: Sender<u32>,
    last: u32, // Last number sent
}

// Could be a Future, it doesn't matter
impl Stream for TestSender {
    type Item = u32;
    type Error = ();

    fn poll(&mut self, cx: &mut task::Context) -> Poll<Option<Self::Item>, Self::Error> {
        match self.tx.start_send(cx, self.last + 1) {
            Err(_) => panic!(),
            Ok(Ok(())) => {
                self.last += 1;
                assert_eq!(Ok(Async::Ready(())), self.tx.flush(cx));
                Ok(Async::Ready(Some(self.last)))
            }
            Ok(Err(_)) => {
                Ok(Async::Pending)
            }
        }
    }
}

/// Single producers, single consumer
#[bench]
fn bounded_1_tx(b: &mut Bencher) {
    let pool = LocalPool::new();
    let mut exec = pool.executor();
    let waker = notify_noop();
    let mut map = task::LocalMap::new();
    let mut cx = task::Context::new(&mut map, &waker, &mut exec);

    b.iter(|| {
        let (tx, mut rx) = channel(0);

        let mut tx = TestSender {
            tx: tx,
            last: 0,
        };

        for i in 0..1000 {
            assert_eq!(Ok(Async::Ready(Some(i + 1))), tx.poll(&mut cx));
            assert_eq!(Ok(Async::Pending), tx.poll(&mut cx));
            assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll(&mut cx));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn bounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        // Each sender can send one item after specified capacity
        let (tx, mut rx) = channel(0);
        let pool = LocalPool::new();
        let mut exec = pool.executor();
        let waker = notify_noop();
        let mut map = task::LocalMap::new();
        let mut cx = task::Context::new(&mut map, &waker, &mut exec);

        let mut tx: Vec<_> = (0..100).map(|_| {
            TestSender {
                tx: tx.clone(),
                last: 0
            }
        }).collect();

        for i in 0..10 {
            for j in 0..tx.len() {
                // Send an item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), tx[j].poll(&mut cx));
                // Then block
                assert_eq!(Ok(Async::Pending), tx[j].poll(&mut cx));
                // Recv the item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll(&mut cx));
            }
        }
    })
}
<commit_msg>Fix futures-channel benches<commit_after>#![feature(test)]

#[macro_use]
extern crate futures;
extern crate futures_channel;
extern crate test;

use futures::task::{self, Wake, Waker};
use futures::executor::LocalPool;
use futures::prelude::*;

use futures_channel::mpsc::unbounded;
use futures_channel::mpsc::channel;
use futures_channel::mpsc::Sender;
use futures_channel::mpsc::UnboundedSender;

use test::Bencher;

fn notify_noop() -> Waker {
    struct Noop;

    impl Wake for Noop {
        fn wake(&self) {}
    }

    const NOOP : &'static Noop = &Noop;

    Waker::from(NOOP)
}

/// Single producer, single consumer
#[bench]
fn unbounded_1_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, mut rx) = unbounded();
        let pool = LocalPool::new();
        let mut exec = pool.executor();
        let waker = notify_noop();
        let mut map = task::LocalMap::new();
        let mut cx = task::Context::new(&mut map, &waker, &mut exec);

        // 1000 iterations to avoid measuring overhead of initialization
        // Result should be divided by 1000
        for i in 0..1000 {

            // Poll, not ready, park
            assert_eq!(Ok(Async::Pending), rx.poll(&mut cx));

            UnboundedSender::unbounded_send(&tx, i).unwrap();

            // Now poll ready
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll(&mut cx));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn unbounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        let (tx, mut rx) = unbounded();
        let pool = LocalPool::new();
        let mut exec = pool.executor();
        let waker = notify_noop();
        let mut map = task::LocalMap::new();
        let mut cx = task::Context::new(&mut map, &waker, &mut exec);

        let tx: Vec<_> = (0..100).map(|_| tx.clone()).collect();

        // 1000 send/recv operations total, result should be divided by 1000
        for _ in 0..10 {
            for i in 0..tx.len() {
                assert_eq!(Ok(Async::Pending), rx.poll(&mut cx));

                UnboundedSender::unbounded_send(&tx[i], i).unwrap();

                assert_eq!(Ok(Async::Ready(Some(i))), rx.poll(&mut cx));
            }
        }
    })
}

#[bench]
fn unbounded_uncontended(b: &mut Bencher) {
    let pool = LocalPool::new();
    let mut exec = pool.executor();
    let waker = notify_noop();
    let mut map = task::LocalMap::new();
    let mut cx = task::Context::new(&mut map, &waker, &mut exec);

    b.iter(|| {
        let (tx, mut rx) = unbounded();

        for i in 0..1000 {
            UnboundedSender::unbounded_send(&tx, i).expect("send");
            // No need to create a task, because poll is not going to park.
            assert_eq!(Ok(Async::Ready(Some(i))), rx.poll(&mut cx));
        }
    })
}

/// A Stream that continuously sends incrementing number of the queue
struct TestSender {
    tx: Sender<u32>,
    last: u32, // Last number sent
}

// Could be a Future, it doesn't matter
impl Stream for TestSender {
    type Item = u32;
    type Error = ();

    fn poll(&mut self, cx: &mut task::Context) -> Poll<Option<Self::Item>, Self::Error> {
        try_ready!(self.tx.poll_ready(cx).map_err(|_| ()));
        self.tx.start_send(self.last + 1).unwrap();
        self.last += 1;
        assert!(self.tx.poll_flush(cx).unwrap().is_ready());
        Ok(Async::Ready(Some(self.last)))
    }
}

/// Single producers, single consumer
#[bench]
fn bounded_1_tx(b: &mut Bencher) {
    let pool = LocalPool::new();
    let mut exec = pool.executor();
    let waker = notify_noop();
    let mut map = task::LocalMap::new();
    let mut cx = task::Context::new(&mut map, &waker, &mut exec);

    b.iter(|| {
        let (tx, mut rx) = channel(0);

        let mut tx = TestSender {
            tx: tx,
            last: 0,
        };

        for i in 0..1000 {
            assert_eq!(Ok(Async::Ready(Some(i + 1))), tx.poll(&mut cx));
            assert_eq!(Ok(Async::Pending), tx.poll(&mut cx));
            assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll(&mut cx));
        }
    })
}

/// 100 producers, single consumer
#[bench]
fn bounded_100_tx(b: &mut Bencher) {
    b.iter(|| {
        // Each sender can send one item after specified capacity
        let (tx, mut rx) = channel(0);
        let pool = LocalPool::new();
        let mut exec = pool.executor();
        let waker = notify_noop();
        let mut map = task::LocalMap::new();
        let mut cx = task::Context::new(&mut map, &waker, &mut exec);

        let mut tx: Vec<_> = (0..100).map(|_| {
            TestSender {
                tx: tx.clone(),
                last: 0
            }
        }).collect();

        for i in 0..10 {
            for j in 0..tx.len() {
                // Send an item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), tx[j].poll(&mut cx));
                // Then block
                assert_eq!(Ok(Async::Pending), tx[j].poll(&mut cx));
                // Recv the item
                assert_eq!(Ok(Async::Ready(Some(i + 1))), rx.poll(&mut cx));
            }
        }
    })
}
<|endoftext|>


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

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do
//! [Cap'n Proto code generation](https://capnproto.org/otherlang.html#how-to-write-compiler-plugins)
//! within a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.14"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

/// Code generated from
/// [schema.capnp](https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;

use std::path::{Path, PathBuf};

// Copied from capnp/src/lib.rs, where this conversion lives behind the "std" feature flag,
// which we don't want to depend on here.
pub(crate) fn convert_io_err(err: std::io::Error) -> capnp::Error {
    use std::io;
    let kind = match err.kind() {
        io::ErrorKind::TimedOut => capnp::ErrorKind::Overloaded,
        io::ErrorKind::BrokenPipe |
        io::ErrorKind::ConnectionRefused |
        io::ErrorKind::ConnectionReset |
        io::ErrorKind::ConnectionAborted |
        io::ErrorKind::NotConnected  => capnp::ErrorKind::Disconnected,
        _ => capnp::ErrorKind::Failed,
    };
    capnp::Error { description: format!("{}", err), kind: kind }
}

fn run_command(mut command: ::std::process::Command, mut code_generation_command: codegen::CodeGenerationCommand) -> ::capnp::Result<()> {
    let mut p = command.spawn().map_err(convert_io_err)?;
    code_generation_command.run(p.stdout.take().unwrap())?;
    let exit_status = p.wait().map_err(convert_io_err)?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    executable_path: Option<PathBuf>,
    output_path: Option<PathBuf>,
    default_parent_module: Vec<String>,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            executable_path: None,
            output_path: None,
            default_parent_module: Vec::new(),
        }
    }

    /// Adds a file to be compiled.
    pub fn file<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<P>(&mut self, prefix: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<P>(&mut self, dir: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import(&mut self) -> &mut CompilerCommand {
        self.no_standard_import = true;
        self
    }

    /// Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.output_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Specify the executable which is used for the 'capnp' tool. When this method is not called, the command looks for a name 'capnp'
    /// on the system (e.g. in working directory or in PATH environment variable).
    pub fn capnp_executable<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>
    {
        self.executable_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Sets the default parent module. This indicates the scope in your crate where you will
    /// add a module containing the generated code. For example, if you set this option to
    /// `vec!["foo".into(), "bar".into()]`, and you are generating code for `baz.capnp`, then your crate
    /// should have this structure:
    ///
    /// ```ignore
    /// pub mod foo {
    ///    pub mod bar {
    ///        pub mod baz_capnp {
    ///            include!(concat!(env!("OUT_DIR"), "/baz_capnp.rs"));
    ///        }
    ///    }
    /// }
    /// ```
    ///
    /// This option can be overridden by the `parentModule` annotation defined in `rust.capnp`.
    ///
    /// If this option is unset, the default is the crate root.
    pub fn default_parent_module(&mut self, default_parent_module: Vec<String>) -> &mut CompilerCommand
    {
        self.default_parent_module = default_parent_module;
        self
    }

    /// Runs the command.
    /// Returns an error if `OUT_DIR` or a custom output directory was not set, or if `capnp compile` fails.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        let mut command = if let Some(executable) = &self.executable_path {
            ::std::process::Command::new(executable)
        } else {
            ::std::process::Command::new("capnp")
        };

        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            command.arg(&format!("{}", file.display()));
        }

        let output_path = if let Some(output_path) = &self.output_path {
            output_path.clone()
        } else {
            // Try `OUT_DIR` by default
            PathBuf::from(::std::env::var("OUT_DIR").map_err(|error| {
                ::capnp::Error::failed(format!(
                    "Could not access `OUT_DIR` environment variable: {}. \
                     You might need to set it up or instead create you own output \
                     structure using `CompilerCommand::output_path`",
                    error
                ))
            })?)
        };

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        let mut code_generation_command = crate::codegen::CodeGenerationCommand::new();
        code_generation_command
            .output_directory(output_path)
            .default_parent_module(self.default_parent_module.clone());

        run_command(command, code_generation_command).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}

#[test]
fn compiler_command_new_no_out_dir() {
    let error = CompilerCommand::new().run().unwrap_err().description;
    assert!(error.starts_with("Could not access `OUT_DIR` environment variable"));
}

#[test]
fn compiler_command_with_output_path_no_out_dir() {
    let error = CompilerCommand::new().output_path("foo").run().unwrap_err().description;
    assert!(error.starts_with("Error while trying to execute `capnp compile`"));
}
<commit_msg>improve error message when attempting to compile a non-existent/inaccessible file.<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do
//! [Cap'n Proto code generation](https://capnproto.org/otherlang.html#how-to-write-compiler-plugins)
//! within a Cargo build. You still need the `capnp` binary (implemented in C++).
//! (If you use a package manager, try looking for a package called
//! `capnproto`.)
//!
//! In your Cargo.toml:
//!
//! ```ignore
//! [package]
//! build = "build.rs"
//!
//! [build-dependencies]
//! capnpc = "0.14"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! fn main() {
//!     capnpc::CompilerCommand::new()
//!         .src_prefix("schema")
//!         .file("schema/foo.capnp")
//!         .file("schema/bar.capnp")
//!         .run().expect("schema compiler command");
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

/// Code generated from
/// [schema.capnp](https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
mod pointer_constants;

use std::path::{Path, PathBuf};

// Copied from capnp/src/lib.rs, where this conversion lives behind the "std" feature flag,
// which we don't want to depend on here.
pub(crate) fn convert_io_err(err: std::io::Error) -> capnp::Error {
    use std::io;
    let kind = match err.kind() {
        io::ErrorKind::TimedOut => capnp::ErrorKind::Overloaded,
        io::ErrorKind::BrokenPipe |
        io::ErrorKind::ConnectionRefused |
        io::ErrorKind::ConnectionReset |
        io::ErrorKind::ConnectionAborted |
        io::ErrorKind::NotConnected  => capnp::ErrorKind::Disconnected,
        _ => capnp::ErrorKind::Failed,
    };
    capnp::Error { description: format!("{}", err), kind: kind }
}

fn run_command(mut command: ::std::process::Command, mut code_generation_command: codegen::CodeGenerationCommand) -> ::capnp::Result<()> {
    let mut p = command.spawn().map_err(convert_io_err)?;
    code_generation_command.run(p.stdout.take().unwrap())?;
    let exit_status = p.wait().map_err(convert_io_err)?;
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!(
            "Non-success exit status: {}",
            exit_status
        )))
    } else {
        Ok(())
    }
}

/// A builder object for schema compiler commands.
pub struct CompilerCommand {
    files: Vec<PathBuf>,
    src_prefixes: Vec<PathBuf>,
    import_paths: Vec<PathBuf>,
    no_standard_import: bool,
    executable_path: Option<PathBuf>,
    output_path: Option<PathBuf>,
    default_parent_module: Vec<String>,
}

impl CompilerCommand {
    /// Creates a new, empty command.
    pub fn new() -> CompilerCommand {
        CompilerCommand {
            files: Vec::new(),
            src_prefixes: Vec::new(),
            import_paths: Vec::new(),
            no_standard_import: false,
            executable_path: None,
            output_path: None,
            default_parent_module: Vec::new(),
        }
    }

    /// Adds a file to be compiled.
    pub fn file<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.files.push(path.as_ref().to_path_buf());
        self
    }

    /// Adds a --src-prefix flag. For all files specified for compilation that start
    /// with `prefix`, removes the prefix when computing output filenames.
    pub fn src_prefix<P>(&mut self, prefix: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.src_prefixes.push(prefix.as_ref().to_path_buf());
        self
    }

    /// Adds an --import_path flag. Adds `dir` to the list of directories searched
    /// for absolute imports.
    pub fn import_path<P>(&mut self, dir: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.import_paths.push(dir.as_ref().to_path_buf());
        self
    }

    /// Adds the --no-standard-import flag, indicating that the default import paths of
    /// /usr/include and /usr/local/include should not bet included.
    pub fn no_standard_import(&mut self) -> &mut CompilerCommand {
        self.no_standard_import = true;
        self
    }

    /// Sets the output directory of generated code. Default is OUT_DIR
    pub fn output_path<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>,
    {
        self.output_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Specify the executable which is used for the 'capnp' tool. When this method is not called, the command looks for a name 'capnp'
    /// on the system (e.g. in working directory or in PATH environment variable).
    pub fn capnp_executable<P>(&mut self, path: P) -> &mut CompilerCommand
    where
        P: AsRef<Path>
    {
        self.executable_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Sets the default parent module. This indicates the scope in your crate where you will
    /// add a module containing the generated code. For example, if you set this option to
    /// `vec!["foo".into(), "bar".into()]`, and you are generating code for `baz.capnp`, then your crate
    /// should have this structure:
    ///
    /// ```ignore
    /// pub mod foo {
    ///    pub mod bar {
    ///        pub mod baz_capnp {
    ///            include!(concat!(env!("OUT_DIR"), "/baz_capnp.rs"));
    ///        }
    ///    }
    /// }
    /// ```
    ///
    /// This option can be overridden by the `parentModule` annotation defined in `rust.capnp`.
    ///
    /// If this option is unset, the default is the crate root.
    pub fn default_parent_module(&mut self, default_parent_module: Vec<String>) -> &mut CompilerCommand
    {
        self.default_parent_module = default_parent_module;
        self
    }

    /// Runs the command.
    /// Returns an error if `OUT_DIR` or a custom output directory was not set, or if `capnp compile` fails.
    pub fn run(&mut self) -> ::capnp::Result<()> {
        let mut command = if let Some(executable) = &self.executable_path {
            ::std::process::Command::new(executable)
        } else {
            ::std::process::Command::new("capnp")
        };

        command.arg("compile").arg("-o").arg("-");

        if self.no_standard_import {
            command.arg("--no-standard-import");
        }

        for import_path in &self.import_paths {
            command.arg(&format!("--import-path={}", import_path.display()));
        }

        for src_prefix in &self.src_prefixes {
            command.arg(&format!("--src-prefix={}", src_prefix.display()));
        }

        for file in &self.files {
            std::fs::metadata(file).map_err(|error| {
                let current_dir = match std::env::current_dir() {
                    Ok(current_dir) => format!("`{}`", current_dir.display()),
                    Err(..) => "<unknown working directory>".to_string(),
                };

                ::capnp::Error::failed(format!(
                    "Unable to stat capnp input file `{}` in working directory {}: {}.  \
                     Please check that the file exists and is accessible for read.",
                    file.display(),
                    current_dir,
                    error
                ))
            })?;

            command.arg(file);
        }

        let output_path = if let Some(output_path) = &self.output_path {
            output_path.clone()
        } else {
            // Try `OUT_DIR` by default
            PathBuf::from(::std::env::var("OUT_DIR").map_err(|error| {
                ::capnp::Error::failed(format!(
                    "Could not access `OUT_DIR` environment variable: {}. \
                     You might need to set it up or instead create you own output \
                     structure using `CompilerCommand::output_path`",
                    error
                ))
            })?)
        };

        command.stdout(::std::process::Stdio::piped());
        command.stderr(::std::process::Stdio::inherit());

        let mut code_generation_command = crate::codegen::CodeGenerationCommand::new();
        code_generation_command
            .output_directory(output_path)
            .default_parent_module(self.default_parent_module.clone());

        run_command(command, code_generation_command).map_err(|error| {
            ::capnp::Error::failed(format!(
                "Error while trying to execute `capnp compile`: {}.  \
                 Please verify that version 0.5.2 or higher of the capnp executable \
                 is installed on your system. See https://capnproto.org/install.html",
                error
            ))
        })
    }
}

#[test]
fn compiler_command_new_no_out_dir() {
    let error = CompilerCommand::new().run().unwrap_err().description;
    assert!(error.starts_with("Could not access `OUT_DIR` environment variable"));
}

#[test]
fn compiler_command_with_output_path_no_out_dir() {
    let error = CompilerCommand::new().output_path("foo").run().unwrap_err().description;
    assert!(error.starts_with("Error while trying to execute `capnp compile`"));
}
<|endoftext|>


<commit_before>// Copyright 2016 The Noise-rs Developers.
//
// 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.

use num_traits::Float;
use math::{Point2, Point3, Point4};
use NoiseModule;
use std::cell::{Cell, RefCell};

/// Noise module that caches the last output value generated by the source
/// module.
///
/// If the input coordinates pased to `Cache::get` are equal to the previous
/// call, the module returns the cached result of the previous call to
/// `Source::get`. Otherwise, `Source::get` is called with the new coordinates,
/// overwriting the cache with the result, and returning the result to the
/// caller.
///
/// Caching a noise module is useful if it is used as a source module for
/// multiple noise modules. If a source module is not cached, the source
/// module will redundantly calculate the same output value once for each
/// noise module in which it is included.
#[derive(Clone, Debug)]
pub struct Cache<Source, T>
    where T: Float,
{
    /// Outputs the value to be cached.
    pub source: Source,

    value: Cell<Option<T>>,

    point: RefCell<Vec<T>>,
}

impl<Source, T> Cache<Source, T>
    where T: Float,
{
    pub fn new(source: Source) -> Cache<Source, T> {
        Cache {
            source: source,
            value: Cell::new(None),
            point: RefCell::new(Vec::new()),
        }
    }
}

impl<Source, T> NoiseModule<Point2<T>> for Cache<Source, T>
    where Source: NoiseModule<Point2<T>, Output = T>,
          T: Float,
{
    type Output = T;

    fn get(&self, point: Point2<T>) -> Self::Output {
        let cached_point: Vec<T>;
        {
            cached_point = self.point.borrow().clone();
        }

        if self.value.get() == None || point[0] != cached_point[0] || point[1] != cached_point[1] {
            self.value.set(Some(self.source.get(point)));
            *self.point.borrow_mut() = point.to_vec();
        }

        return self.value.get().unwrap();
    }
}

impl<Source, T> NoiseModule<Point3<T>> for Cache<Source, T>
    where Source: NoiseModule<Point3<T>, Output = T>,
          T: Float,
{
    type Output = T;

    fn get(&self, point: Point3<T>) -> Self::Output {
        let cached_point: Vec<T>;
        {
            cached_point = self.point.borrow().clone();
        }

        if self.value.get() == None || point[0] != cached_point[0] ||
           point[1] != cached_point[1] || point[2] != cached_point[2] {
            self.value.set(Some(self.source.get(point)));
            *self.point.borrow_mut() = point.to_vec();
        }

        return self.value.get().unwrap();
    }
}

impl<Source, T> NoiseModule<Point4<T>> for Cache<Source, T>
    where Source: NoiseModule<Point4<T>, Output = T>,
          T: Float,
{
    type Output = T;

    fn get(&self, point: Point4<T>) -> Self::Output {
        let cached_point: Vec<T>;
        {
            cached_point = self.point.borrow().clone();
        }

        if self.value.get() == None || point[0] != cached_point[0] ||
           point[1] != cached_point[1] || point[2] != cached_point[2] ||
           point[3] != cached_point[3] {
            self.value.set(Some(self.source.get(point)));
            *self.point.borrow_mut() = point.to_vec();
        }

        return self.value.get().unwrap();
    }
}
<commit_msg>Simplify Cache internals<commit_after>// Copyright 2016 The Noise-rs Developers.
//
// 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.

use num_traits::Float;
use math::{Point2, Point3, Point4};
use NoiseModule;
use std::cell::{Cell, RefCell};

/// Noise module that caches the last output value generated by the source
/// module.
///
/// If the input coordinates pased to `Cache::get` are equal to the previous
/// call, the module returns the cached result of the previous call to
/// `Source::get`. Otherwise, `Source::get` is called with the new coordinates,
/// overwriting the cache with the result, and returning the result to the
/// caller.
///
/// Caching a noise module is useful if it is used as a source module for
/// multiple noise modules. If a source module is not cached, the source
/// module will redundantly calculate the same output value once for each
/// noise module in which it is included.
#[derive(Clone, Debug)]
pub struct Cache<Source, T>
    where T: Float,
{
    /// Outputs the value to be cached.
    pub source: Source,

    value: Cell<Option<T>>,

    point: RefCell<Vec<T>>,
}

impl<Source, T> Cache<Source, T>
    where T: Float,
{
    pub fn new(source: Source) -> Cache<Source, T> {
        Cache {
            source: source,
            value: Cell::new(None),
            point: RefCell::new(Vec::new()),
        }
    }
}

impl<Source, T> NoiseModule<Point2<T>> for Cache<Source, T>
    where Source: NoiseModule<Point2<T>, Output = T>,
          T: Float,
{
    type Output = T;

    fn get(&self, point: Point2<T>) -> Self::Output {
        match self.value.get() {
            Some(value) if *self.point.borrow() == point => value,
            Some(_) | None => {
                let value = self.source.get(point);
                self.value.set(Some(value));

                *self.point.borrow_mut() = point.to_vec();

                value
            }
        }
    }
}

impl<Source, T> NoiseModule<Point3<T>> for Cache<Source, T>
    where Source: NoiseModule<Point3<T>, Output = T>,
          T: Float,
{
    type Output = T;

    fn get(&self, point: Point3<T>) -> Self::Output {
        match self.value.get() {
            Some(value) if *self.point.borrow() == point => value,
            Some(_) | None => {
                let value = self.source.get(point);
                self.value.set(Some(value));

                *self.point.borrow_mut() = point.to_vec();

                value
            }
        }
    }
}

impl<Source, T> NoiseModule<Point4<T>> for Cache<Source, T>
    where Source: NoiseModule<Point4<T>, Output = T>,
          T: Float,
{
    type Output = T;

    fn get(&self, point: Point4<T>) -> Self::Output {
        match self.value.get() {
            Some(value) if *self.point.borrow() == point => value,
            Some(_) | None => {
                let value = self.source.get(point);
                self.value.set(Some(value));

                *self.point.borrow_mut() = point.to_vec();

                value
            }
        }
    }
}
<|endoftext|>