<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 in memory.
                pub fn new<P: PixelValue, T: {data_type}>(display: &::Display, data: {param})
                    -> {name}
                {{
            ", data_type = data_type, param = param, name = name)).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 `let format = ...` line
        (writeln!(dest, "let format = PixelValue::get_format(None::<P>);")).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
        (writeln!(dest, "let client_format = PixelValue::get_format(None::<P>);")).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();

        // 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>Specify that Texture::new generates mipmaps<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();

        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 `let format = ...` line
        (writeln!(dest, "let format = PixelValue::get_format(None::<P>);")).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
        (writeln!(dest, "let client_format = PixelValue::get_format(None::<P>);")).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();

        // 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();
}
<|endoftext|>


<commit_before><commit_msg>add helpers module with random01 function and test<commit_after>/*!
helper functions used by this crate
whose utility surpasses the boundaries of this crate.
*/

extern crate rand;
use self::rand::{Rng, Closed01, Rand};

mod repeatedly;
pub use self::repeatedly::{Repeatedly, repeatedly};

/// returns a random number between `0.` (inclusive) and `1.` (inclusive)
pub fn random01<T, R>(rng: &mut R) -> T
    where Closed01<T>: Rand,
          R: Rng
{
    let Closed01(random) = rng.gen::<Closed01<T>>();
    random
}

#[test]
fn test_random01() {
    use self::rand::{StdRng, SeedableRng};

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);
    let r: f64 = random01(&mut rng);
    assert_eq!(r, 0.5162139860908154);
}
<|endoftext|>


<commit_before><commit_msg>Adding some examples for my internship presentation.<commit_after>// Examples from Eric's internship final presentation.
//
// Code is easier to write in emacs, and it's good to be sure all the
// code samples compile (or not) as they should.

import double_buffer::client::*;
import double_buffer::give_buffer;

macro_rules! select_if {
    {
        $index:expr,
        $count:expr,
        $port:path => [
            $($message:path$(($($x: ident),+))dont_type_this*
              -> $next:ident $e:expr),+
        ],
        $( $ports:path => [
            $($messages:path$(($($xs: ident),+))dont_type_this*
              -> $nexts:ident $es:expr),+
        ], )*
    } => {
        log_syntax!{select_if1};
        if $index == $count {
            match move pipes::try_recv($port) {
              $(some($message($($(copy $x,)+)* next)) => {
                // FIXME (#2329) we really want move out of enum here.
                let $next = unsafe { let x <- *ptr::addr_of(next); x };
                $e
              })+
              _ => fail
            }
        } else {
            select_if!{
                $index,
                $count + 1,
                $( $ports => [
                    $($messages$(($($xs),+))dont_type_this*
                      -> $nexts $es),+
                ], )*
            }
        }
    };

    {
        $index:expr,
        $count:expr,
    } => {
        log_syntax!{select_if2};
        fail
    }
}

macro_rules! select {
    {
        $( $port:path => {
            $($message:path$(($($x: ident),+))dont_type_this*
              -> $next:ident $e:expr),+
        } )+
    } => {
        let index = pipes::selecti([$(($port).header()),+]/_);
        log_syntax!{select};
        log_syntax!{
        select_if!{index, 0, $( $port => [
            $($message$(($($x),+))dont_type_this* -> $next $e),+
        ], )+}
        };
        select_if!{index, 0, $( $port => [
            $($message$(($($x),+))dont_type_this* -> $next $e),+
        ], )+}
    }
}

// Types and protocols
struct Buffer {
    foo: ();

    drop { }
}

proto! double_buffer {
    acquire:send {
        request -> wait_buffer
    }

    wait_buffer:recv {
        give_buffer(Buffer) -> release
    }

    release:send {
        release(Buffer) -> acquire
    }
}

// Code examples
fn render(_buffer: &Buffer) {
    // A dummy function.
}

fn draw_frame(+channel: double_buffer::client::acquire) {
    let channel = request(channel);
    select! {
        channel => {
            give_buffer(buffer) -> channel {
                render(&buffer);
                release(channel, move buffer)
            }
        }
    };
}

fn draw_two_frames(+channel: double_buffer::client::acquire) {
    let channel = request(channel);
    let channel = select! {
        channel => {
            give_buffer(buffer) -> channel {
                render(&buffer);
                release(channel, move buffer)
            }
        }
    };
    let channel = request(channel);
    select! {
        channel => {
            give_buffer(buffer) -> channel {
                render(&buffer);
                release(channel, move buffer)
            }
        }
    };
}

#[cfg(bad1)]
fn draw_two_frames_bad1(+channel: double_buffer::client::acquire) {
    let channel = request(channel);
    let channel = select! {
        channel => {
            give_buffer(buffer) -> channel {
                render(&buffer);
                channel
            }
        }
    };
    let channel = request(channel);
    select! {
        channel => {
            give_buffer(buffer) -> channel {
                render(&buffer);
                release(channel, move buffer)
            }
        }
    };
}

#[cfg(bad2)]
fn draw_two_frames_bad2(+channel: double_buffer::client::acquire) {
    let channel = request(channel);
    select! {
        channel => {
            give_buffer(buffer) -> channel {
                render(&buffer);
                release(channel, move buffer);
                render(&buffer);
                release(channel, move buffer);
            }
        }
    };
}

fn main() { }<|endoftext|>


<commit_before><commit_msg>Fix event queuing<commit_after><|endoftext|>


<commit_before>

/* Simple getopt alternative. Construct a vector of options, either by using
 * reqopt, optopt, and optflag or by building them from components yourself,
 * and pass them to getopts, along with a vector of actual arguments (not
 * including argv[0]). You'll either get a failure code back, or a match.
 * You'll have to verify whether the amount of 'free' arguments in the match
 * is what you expect. Use opt_* accessors (bottom of the file) to get
 * argument values out of the match object.
 */
import option::some;
import option::none;
export opt;
export reqopt;
export optopt;
export optflag;
export optflagopt;
export optmulti;
export getopts;
export getopts_ivec;
export result;
export success;
export failure;
export match;
export fail_;
export fail_str;
export opt_present;
export opt_str;
export opt_strs;
export opt_maybe_str;
export opt_default;

tag name { long(str); short(char); }

tag hasarg { yes; no; maybe; }

tag occur { req; optional; multi; }

type opt = {name: name, hasarg: hasarg, occur: occur};

fn mkname(nm: str) -> name {
    ret if str::char_len(nm) == 1u {
            short(str::char_at(nm, 0u))
        } else { long(nm) };
}

fn reqopt(name: str) -> opt {
    ret {name: mkname(name), hasarg: yes, occur: req};
}

fn optopt(name: str) -> opt {
    ret {name: mkname(name), hasarg: yes, occur: optional};
}

fn optflag(name: str) -> opt {
    ret {name: mkname(name), hasarg: no, occur: optional};
}

fn optflagopt(name: str) -> opt {
    ret {name: mkname(name), hasarg: maybe, occur: optional};
}

fn optmulti(name: str) -> opt {
    ret {name: mkname(name), hasarg: yes, occur: multi};
}

tag optval { val(str); given; }

type match = {opts: opt[], vals: optval[][mutable ], free: vec[str]};

fn is_arg(arg: str) -> bool {
    ret str::byte_len(arg) > 1u && arg.(0) == '-' as u8;
}

fn name_str(nm: name) -> str {
    ret alt nm { short(ch) { str::from_char(ch) } long(s) { s } };
}

fn find_opt(opts: &opt[], nm: name) -> option::t[uint] {
    let i = 0u;
    let l = ivec::len[opt](opts);
    while i < l { if opts.(i).name == nm { ret some[uint](i); } i += 1u; }
    ret none[uint];
}

tag fail_ {
    argument_missing(str);
    unrecognized_option(str);
    option_missing(str);
    option_duplicated(str);
    unexpected_argument(str);
}

fn fail_str(f: fail_) -> str {
    ret alt f {
          argument_missing(nm) { "Argument to option '" + nm + "' missing." }
          unrecognized_option(nm) { "Unrecognized option: '" + nm + "'." }
          option_missing(nm) { "Required option '" + nm + "' missing." }
          option_duplicated(nm) {
            "Option '" + nm + "' given more than once."
          }
          unexpected_argument(nm) {
            "Option " + nm + " does not take an argument."
          }
        };
}

tag result { success(match); failure(fail_); }

fn getopts(args: vec[str], opts: vec[opt]) -> result {
    // FIXME: Remove this vec->ivec conversion.
    let args_ivec = ~[];
    let opts_ivec = ~[];
    for arg: str  in args { args_ivec += ~[arg]; }
    for o: opt  in opts { opts_ivec += ~[o]; }
    ret getopts_ivec(args_ivec, opts_ivec);
}

fn getopts_ivec(args: &str[], opts: &opt[]) -> result {
    let n_opts = ivec::len[opt](opts);
    fn f(x: uint) -> optval[] { ret ~[]; }
    let vals = ivec::init_fn_mut[optval[]](f, n_opts);
    let free: vec[str] = [];
    let l = ivec::len[str](args);
    let i = 0u;
    while i < l {
        let cur = args.(i);
        let curlen = str::byte_len(cur);
        if !is_arg(cur) {
            free += [cur];
        } else if (str::eq(cur, "--")) {
            let j = i + 1u;
            while j < l { free += [args.(j)]; j += 1u; }
            break;
        } else {
            let names;
            let i_arg = option::none[str];
            if cur.(1) == '-' as u8 {
                let tail = str::slice(cur, 2u, curlen);
                let eq = str::index(tail, '=' as u8);
                if eq == -1 {
                    names = ~[long(tail)];
                } else {
                    names = ~[long(str::slice(tail, 0u, eq as uint))];
                    i_arg =
                        option::some[str](str::slice(tail, (eq as uint) + 1u,
                                                     curlen - 2u));
                }
            } else {
                let j = 1u;
                names = ~[];
                while j < curlen {
                    let range = str::char_range_at(cur, j);
                    names += ~[short(range.ch)];
                    j = range.next;
                }
            }
            let name_pos = 0u;
            for nm: name  in names {
                name_pos += 1u;
                let optid;
                alt find_opt(opts, nm) {
                  some(id) { optid = id; }
                  none. { ret failure(unrecognized_option(name_str(nm))); }
                }
                alt opts.(optid).hasarg {
                  no. {
                    if !option::is_none[str](i_arg) {
                        ret failure(unexpected_argument(name_str(nm)));
                    }
                    vals.(optid) += ~[given];
                  }
                  maybe. {
                    if !option::is_none[str](i_arg) {
                        vals.(optid) += ~[val(option::get(i_arg))];
                    } else if (name_pos < ivec::len[name](names) ||
                                   i + 1u == l || is_arg(args.(i + 1u))) {
                        vals.(optid) += ~[given];
                    } else { i += 1u; vals.(optid) += ~[val(args.(i))]; }
                  }
                  yes. {
                    if !option::is_none[str](i_arg) {
                        vals.(optid) += ~[val(option::get[str](i_arg))];
                    } else if (i + 1u == l) {
                        ret failure(argument_missing(name_str(nm)));
                    } else { i += 1u; vals.(optid) += ~[val(args.(i))]; }
                  }
                }
            }
        }
        i += 1u;
    }
    i = 0u;
    while i < n_opts {
        let n = ivec::len[optval](vals.(i));
        let occ = opts.(i).occur;
        if occ == req {
            if n == 0u {
                ret failure(option_missing(name_str(opts.(i).name)));
            }
        }
        if occ != multi {
            if n > 1u {
                ret failure(option_duplicated(name_str(opts.(i).name)));
            }
        }
        i += 1u;
    }
    ret success({opts: opts, vals: vals, free: free});
}

fn opt_vals(m: match, nm: str) -> optval[] {
    ret alt find_opt(m.opts, mkname(nm)) {
          some(id) { m.vals.(id) }
          none. { log_err "No option '" + nm + "' defined."; fail }
        };
}

fn opt_val(m: match, nm: str) -> optval { ret opt_vals(m, nm).(0); }

fn opt_present(m: match, nm: str) -> bool {
    ret ivec::len[optval](opt_vals(m, nm)) > 0u;
}

fn opt_str(m: match, nm: str) -> str {
    ret alt opt_val(m, nm) { val(s) { s } _ { fail } };
}

fn opt_strs(m: match, nm: str) -> vec[str] {
    let acc: vec[str] = [];
    for v: optval  in opt_vals(m, nm) {
        alt v { val(s) { acc += [s]; } _ { } }
    }
    ret acc;
}

fn opt_strs_ivec(m: match, nm: str) -> str[] {
    let acc: str[] = ~[];
    for v: optval  in opt_vals(m, nm) {
        alt v { val(s) { acc += ~[s]; } _ { } }
    }
    ret acc;
}

fn opt_maybe_str(m: match, nm: str) -> option::t[str] {
    let vals = opt_vals(m, nm);
    if ivec::len[optval](vals) == 0u { ret none[str]; }
    ret alt vals.(0) { val(s) { some[str](s) } _ { none[str] } };
}

/// Returns none if the option was not present, `def` if the option was
/// present but no argument was provided, and the argument if the option was
/// present and an argument was provided.
fn opt_default(m: match, nm: str, def: str) -> option::t[str] {
    let vals = opt_vals(m, nm);
    if ivec::len[optval](vals) == 0u { ret none[str]; }
    ret alt vals.(0) { val(s) { some[str](s) } _ { some[str](def) } }
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>stdlib: Pass getopt matches by alias<commit_after>

/* Simple getopt alternative. Construct a vector of options, either by using
 * reqopt, optopt, and optflag or by building them from components yourself,
 * and pass them to getopts, along with a vector of actual arguments (not
 * including argv[0]). You'll either get a failure code back, or a match.
 * You'll have to verify whether the amount of 'free' arguments in the match
 * is what you expect. Use opt_* accessors (bottom of the file) to get
 * argument values out of the match object.
 */
import option::some;
import option::none;
export opt;
export reqopt;
export optopt;
export optflag;
export optflagopt;
export optmulti;
export getopts;
export getopts_ivec;
export result;
export success;
export failure;
export match;
export fail_;
export fail_str;
export opt_present;
export opt_str;
export opt_strs;
export opt_maybe_str;
export opt_default;

tag name { long(str); short(char); }

tag hasarg { yes; no; maybe; }

tag occur { req; optional; multi; }

type opt = {name: name, hasarg: hasarg, occur: occur};

fn mkname(nm: str) -> name {
    ret if str::char_len(nm) == 1u {
            short(str::char_at(nm, 0u))
        } else { long(nm) };
}

fn reqopt(name: str) -> opt {
    ret {name: mkname(name), hasarg: yes, occur: req};
}

fn optopt(name: str) -> opt {
    ret {name: mkname(name), hasarg: yes, occur: optional};
}

fn optflag(name: str) -> opt {
    ret {name: mkname(name), hasarg: no, occur: optional};
}

fn optflagopt(name: str) -> opt {
    ret {name: mkname(name), hasarg: maybe, occur: optional};
}

fn optmulti(name: str) -> opt {
    ret {name: mkname(name), hasarg: yes, occur: multi};
}

tag optval { val(str); given; }

type match = {opts: opt[], vals: optval[][mutable ], free: vec[str]};

fn is_arg(arg: str) -> bool {
    ret str::byte_len(arg) > 1u && arg.(0) == '-' as u8;
}

fn name_str(nm: name) -> str {
    ret alt nm { short(ch) { str::from_char(ch) } long(s) { s } };
}

fn find_opt(opts: &opt[], nm: name) -> option::t[uint] {
    let i = 0u;
    let l = ivec::len[opt](opts);
    while i < l { if opts.(i).name == nm { ret some[uint](i); } i += 1u; }
    ret none[uint];
}

tag fail_ {
    argument_missing(str);
    unrecognized_option(str);
    option_missing(str);
    option_duplicated(str);
    unexpected_argument(str);
}

fn fail_str(f: fail_) -> str {
    ret alt f {
          argument_missing(nm) { "Argument to option '" + nm + "' missing." }
          unrecognized_option(nm) { "Unrecognized option: '" + nm + "'." }
          option_missing(nm) { "Required option '" + nm + "' missing." }
          option_duplicated(nm) {
            "Option '" + nm + "' given more than once."
          }
          unexpected_argument(nm) {
            "Option " + nm + " does not take an argument."
          }
        };
}

tag result { success(match); failure(fail_); }

fn getopts(args: vec[str], opts: vec[opt]) -> result {
    // FIXME: Remove this vec->ivec conversion.
    let args_ivec = ~[];
    let opts_ivec = ~[];
    for arg: str  in args { args_ivec += ~[arg]; }
    for o: opt  in opts { opts_ivec += ~[o]; }
    ret getopts_ivec(args_ivec, opts_ivec);
}

fn getopts_ivec(args: &str[], opts: &opt[]) -> result {
    let n_opts = ivec::len[opt](opts);
    fn f(x: uint) -> optval[] { ret ~[]; }
    let vals = ivec::init_fn_mut[optval[]](f, n_opts);
    let free: vec[str] = [];
    let l = ivec::len[str](args);
    let i = 0u;
    while i < l {
        let cur = args.(i);
        let curlen = str::byte_len(cur);
        if !is_arg(cur) {
            free += [cur];
        } else if (str::eq(cur, "--")) {
            let j = i + 1u;
            while j < l { free += [args.(j)]; j += 1u; }
            break;
        } else {
            let names;
            let i_arg = option::none[str];
            if cur.(1) == '-' as u8 {
                let tail = str::slice(cur, 2u, curlen);
                let eq = str::index(tail, '=' as u8);
                if eq == -1 {
                    names = ~[long(tail)];
                } else {
                    names = ~[long(str::slice(tail, 0u, eq as uint))];
                    i_arg =
                        option::some[str](str::slice(tail, (eq as uint) + 1u,
                                                     curlen - 2u));
                }
            } else {
                let j = 1u;
                names = ~[];
                while j < curlen {
                    let range = str::char_range_at(cur, j);
                    names += ~[short(range.ch)];
                    j = range.next;
                }
            }
            let name_pos = 0u;
            for nm: name  in names {
                name_pos += 1u;
                let optid;
                alt find_opt(opts, nm) {
                  some(id) { optid = id; }
                  none. { ret failure(unrecognized_option(name_str(nm))); }
                }
                alt opts.(optid).hasarg {
                  no. {
                    if !option::is_none[str](i_arg) {
                        ret failure(unexpected_argument(name_str(nm)));
                    }
                    vals.(optid) += ~[given];
                  }
                  maybe. {
                    if !option::is_none[str](i_arg) {
                        vals.(optid) += ~[val(option::get(i_arg))];
                    } else if (name_pos < ivec::len[name](names) ||
                                   i + 1u == l || is_arg(args.(i + 1u))) {
                        vals.(optid) += ~[given];
                    } else { i += 1u; vals.(optid) += ~[val(args.(i))]; }
                  }
                  yes. {
                    if !option::is_none[str](i_arg) {
                        vals.(optid) += ~[val(option::get[str](i_arg))];
                    } else if (i + 1u == l) {
                        ret failure(argument_missing(name_str(nm)));
                    } else { i += 1u; vals.(optid) += ~[val(args.(i))]; }
                  }
                }
            }
        }
        i += 1u;
    }
    i = 0u;
    while i < n_opts {
        let n = ivec::len[optval](vals.(i));
        let occ = opts.(i).occur;
        if occ == req {
            if n == 0u {
                ret failure(option_missing(name_str(opts.(i).name)));
            }
        }
        if occ != multi {
            if n > 1u {
                ret failure(option_duplicated(name_str(opts.(i).name)));
            }
        }
        i += 1u;
    }
    ret success({opts: opts, vals: vals, free: free});
}

fn opt_vals(m: &match, nm: str) -> optval[] {
    ret alt find_opt(m.opts, mkname(nm)) {
          some(id) { m.vals.(id) }
          none. { log_err "No option '" + nm + "' defined."; fail }
        };
}

fn opt_val(m: &match, nm: str) -> optval { ret opt_vals(m, nm).(0); }

fn opt_present(m: &match, nm: str) -> bool {
    ret ivec::len[optval](opt_vals(m, nm)) > 0u;
}

fn opt_str(m: &match, nm: str) -> str {
    ret alt opt_val(m, nm) { val(s) { s } _ { fail } };
}

fn opt_strs(m: &match, nm: str) -> vec[str] {
    let acc: vec[str] = [];
    for v: optval  in opt_vals(m, nm) {
        alt v { val(s) { acc += [s]; } _ { } }
    }
    ret acc;
}

fn opt_strs_ivec(m: &match, nm: str) -> str[] {
    let acc: str[] = ~[];
    for v: optval  in opt_vals(m, nm) {
        alt v { val(s) { acc += ~[s]; } _ { } }
    }
    ret acc;
}

fn opt_maybe_str(m: &match, nm: str) -> option::t[str] {
    let vals = opt_vals(m, nm);
    if ivec::len[optval](vals) == 0u { ret none[str]; }
    ret alt vals.(0) { val(s) { some[str](s) } _ { none[str] } };
}

/// Returns none if the option was not present, `def` if the option was
/// present but no argument was provided, and the argument if the option was
/// present and an argument was provided.
fn opt_default(m: &match, nm: str, def: str) -> option::t[str] {
    let vals = opt_vals(m, nm);
    if ivec::len[optval](vals) == 0u { ret none[str]; }
    ret alt vals.(0) { val(s) { some[str](s) } _ { some[str](def) } }
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>#[doc = "Unsafe pointer utility functions"];

export addr_of;
export mut_addr_of;
export offset;
export mut_offset;
export null;
export memcpy;
export memmove;

import libc::c_void;

#[nolink]
#[abi = "cdecl"]
native mod libc_ {
    #[rust_stack]
    fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn addr_of<T>(val: T) -> *T;
}

#[doc = "Get an unsafe pointer to a value"]
#[inline(always)]
fn addr_of<T>(val: T) -> *T { rusti::addr_of(val) }

#[doc = "Get an unsafe mut pointer to a value"]
#[inline(always)]
fn mut_addr_of<T>(val: T) -> *mut T unsafe {
    unsafe::reinterpret_cast(rusti::addr_of(val))
}

#[doc = "Calculate the offset from a pointer"]
#[inline(always)]
fn offset<T>(ptr: *T, count: uint) -> *T unsafe {
    (ptr as uint + count * sys::size_of::<T>()) as *T
}

#[doc = "Calculate the offset from a mut pointer"]
#[inline(always)]
fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
    (ptr as uint + count * sys::size_of::<T>()) as *mut T
}

#[doc = "Create an unsafe null pointer"]
#[inline(always)]
pure fn null<T>() -> *T unsafe { ret unsafe::reinterpret_cast(0u); }

#[doc = "Returns true if the pointer is equal to the null pointer"]
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }

#[doc = "Returns true if the pointer is not equal to the null pointer"]
pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may not overlap.
"]
#[inline(always)]
unsafe fn memcpy<T>(dst: *T, src: *T, count: uint) {
    let n = count * sys::size_of::<T>();
    libc_::memcpy(dst as *c_void, src as *c_void, n);
}

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may overlap.
"]
#[inline(always)]
unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memmove(dst as *c_void, src as *c_void, n);
}

#[test]
fn test() unsafe {
    type pair = {mut fst: int, mut snd: int};
    let p = {mut fst: 10, mut snd: 20};
    let pptr: *mut pair = mut_addr_of(p);
    let iptr: *mut int = unsafe::reinterpret_cast(pptr);
    assert (*iptr == 10);;
    *iptr = 30;
    assert (*iptr == 30);
    assert (p.fst == 30);;

    *pptr = {mut fst: 50, mut snd: 60};
    assert (*iptr == 50);
    assert (p.fst == 50);
    assert (p.snd == 60);

    let v0 = [32000u16, 32001u16, 32002u16];
    let v1 = [0u16, 0u16, 0u16];

    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 1u),
                ptr::offset(vec::unsafe::to_ptr(v0), 1u), 1u);
    assert (v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(vec::unsafe::to_ptr(v1),
                ptr::offset(vec::unsafe::to_ptr(v0), 2u), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 2u),
                vec::unsafe::to_ptr(v0), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16);
}<commit_msg>core: Export is_null, is_not_null<commit_after>#[doc = "Unsafe pointer utility functions"];

export addr_of;
export mut_addr_of;
export offset;
export mut_offset;
export null;
export is_null;
export is_not_null;
export memcpy;
export memmove;

import libc::c_void;

#[nolink]
#[abi = "cdecl"]
native mod libc_ {
    #[rust_stack]
    fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn addr_of<T>(val: T) -> *T;
}

#[doc = "Get an unsafe pointer to a value"]
#[inline(always)]
fn addr_of<T>(val: T) -> *T { rusti::addr_of(val) }

#[doc = "Get an unsafe mut pointer to a value"]
#[inline(always)]
fn mut_addr_of<T>(val: T) -> *mut T unsafe {
    unsafe::reinterpret_cast(rusti::addr_of(val))
}

#[doc = "Calculate the offset from a pointer"]
#[inline(always)]
fn offset<T>(ptr: *T, count: uint) -> *T unsafe {
    (ptr as uint + count * sys::size_of::<T>()) as *T
}

#[doc = "Calculate the offset from a mut pointer"]
#[inline(always)]
fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
    (ptr as uint + count * sys::size_of::<T>()) as *mut T
}

#[doc = "Create an unsafe null pointer"]
#[inline(always)]
pure fn null<T>() -> *T unsafe { ret unsafe::reinterpret_cast(0u); }

#[doc = "Returns true if the pointer is equal to the null pointer"]
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }

#[doc = "Returns true if the pointer is not equal to the null pointer"]
pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may not overlap.
"]
#[inline(always)]
unsafe fn memcpy<T>(dst: *T, src: *T, count: uint) {
    let n = count * sys::size_of::<T>();
    libc_::memcpy(dst as *c_void, src as *c_void, n);
}

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may overlap.
"]
#[inline(always)]
unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memmove(dst as *c_void, src as *c_void, n);
}

#[test]
fn test() unsafe {
    type pair = {mut fst: int, mut snd: int};
    let p = {mut fst: 10, mut snd: 20};
    let pptr: *mut pair = mut_addr_of(p);
    let iptr: *mut int = unsafe::reinterpret_cast(pptr);
    assert (*iptr == 10);;
    *iptr = 30;
    assert (*iptr == 30);
    assert (p.fst == 30);;

    *pptr = {mut fst: 50, mut snd: 60};
    assert (*iptr == 50);
    assert (p.fst == 50);
    assert (p.snd == 60);

    let v0 = [32000u16, 32001u16, 32002u16];
    let v1 = [0u16, 0u16, 0u16];

    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 1u),
                ptr::offset(vec::unsafe::to_ptr(v0), 1u), 1u);
    assert (v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(vec::unsafe::to_ptr(v1),
                ptr::offset(vec::unsafe::to_ptr(v0), 2u), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 2u),
                vec::unsafe::to_ptr(v0), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16);
}<|endoftext|>


<commit_before>//! Simple ANSI color library

use core::Option;

// FIXME (#2807): Windows support.

const color_black: u8 = 0u8;
const color_red: u8 = 1u8;
const color_green: u8 = 2u8;
const color_yellow: u8 = 3u8;
const color_blue: u8 = 4u8;
const color_magenta: u8 = 5u8;
const color_cyan: u8 = 6u8;
const color_light_gray: u8 = 7u8;
const color_light_grey: u8 = 7u8;
const color_dark_gray: u8 = 8u8;
const color_dark_grey: u8 = 8u8;
const color_bright_red: u8 = 9u8;
const color_bright_green: u8 = 10u8;
const color_bright_yellow: u8 = 11u8;
const color_bright_blue: u8 = 12u8;
const color_bright_magenta: u8 = 13u8;
const color_bright_cyan: u8 = 14u8;
const color_bright_white: u8 = 15u8;

fn esc(writer: io::Writer) { writer.write(~[0x1bu8, '[' as u8]); }

/// Reset the foreground and background colors to default
fn reset(writer: io::Writer) {
    esc(writer);
    writer.write(~['0' as u8, 'm' as u8]);
}

/// Returns true if the terminal supports color
fn color_supported() -> bool {
    let supported_terms = ~[~"xterm-color", ~"xterm",
                           ~"screen-bce", ~"xterm-256color"];
    return match os::getenv(~"TERM") {
          option::Some(env) => {
            for vec::each(supported_terms) |term| {
                if term == env { return true; }
            }
            false
          }
          option::None => false
        };
}

fn set_color(writer: io::Writer, first_char: u8, color: u8) {
    assert (color < 16u8);
    esc(writer);
    let mut color = color;
    if color >= 8u8 { writer.write(~['1' as u8, ';' as u8]); color -= 8u8; }
    writer.write(~[first_char, ('0' as u8) + color, 'm' as u8]);
}

/// Set the foreground color
fn fg(writer: io::Writer, color: u8) {
    return set_color(writer, '3' as u8, color);
}

/// Set the background color
fn bg(writer: io::Writer, color: u8) {
    return set_color(writer, '4' as u8, color);
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Confirm demoding of term.rs<commit_after>//! Simple ANSI color library
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

use core::Option;

// FIXME (#2807): Windows support.

const color_black: u8 = 0u8;
const color_red: u8 = 1u8;
const color_green: u8 = 2u8;
const color_yellow: u8 = 3u8;
const color_blue: u8 = 4u8;
const color_magenta: u8 = 5u8;
const color_cyan: u8 = 6u8;
const color_light_gray: u8 = 7u8;
const color_light_grey: u8 = 7u8;
const color_dark_gray: u8 = 8u8;
const color_dark_grey: u8 = 8u8;
const color_bright_red: u8 = 9u8;
const color_bright_green: u8 = 10u8;
const color_bright_yellow: u8 = 11u8;
const color_bright_blue: u8 = 12u8;
const color_bright_magenta: u8 = 13u8;
const color_bright_cyan: u8 = 14u8;
const color_bright_white: u8 = 15u8;

fn esc(writer: io::Writer) { writer.write(~[0x1bu8, '[' as u8]); }

/// Reset the foreground and background colors to default
fn reset(writer: io::Writer) {
    esc(writer);
    writer.write(~['0' as u8, 'm' as u8]);
}

/// Returns true if the terminal supports color
fn color_supported() -> bool {
    let supported_terms = ~[~"xterm-color", ~"xterm",
                           ~"screen-bce", ~"xterm-256color"];
    return match os::getenv(~"TERM") {
          option::Some(env) => {
            for vec::each(supported_terms) |term| {
                if term == env { return true; }
            }
            false
          }
          option::None => false
        };
}

fn set_color(writer: io::Writer, first_char: u8, color: u8) {
    assert (color < 16u8);
    esc(writer);
    let mut color = color;
    if color >= 8u8 { writer.write(~['1' as u8, ';' as u8]); color -= 8u8; }
    writer.write(~[first_char, ('0' as u8) + color, 'm' as u8]);
}

/// Set the foreground color
fn fg(writer: io::Writer, color: u8) {
    return set_color(writer, '3' as u8, color);
}

/// Set the background color
fn bg(writer: io::Writer, color: u8) {
    return set_color(writer, '4' as u8, color);
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ## The Cleanup module
//!
//! The cleanup module tracks what values need to be cleaned up as scopes
//! are exited, either via panic or just normal control flow. The basic
//! idea is that the function context maintains a stack of cleanup scopes
//! that are pushed/popped as we traverse the AST tree. There is typically
//! at least one cleanup scope per AST node; some AST nodes may introduce
//! additional temporary scopes.
//!
//! Cleanup items can be scheduled into any of the scopes on the stack.
//! Typically, when a scope is popped, we will also generate the code for
//! each of its cleanups at that time. This corresponds to a normal exit
//! from a block (for example, an expression completing evaluation
//! successfully without panic). However, it is also possible to pop a
//! block *without* executing its cleanups; this is typically used to
//! guard intermediate values that must be cleaned up on panic, but not
//! if everything goes right. See the section on custom scopes below for
//! more details.
//!
//! Cleanup scopes come in three kinds:
//!
//! - **AST scopes:** each AST node in a function body has a corresponding
//!   AST scope. We push the AST scope when we start generate code for an AST
//!   node and pop it once the AST node has been fully generated.
//! - **Loop scopes:** loops have an additional cleanup scope. Cleanups are
//!   never scheduled into loop scopes; instead, they are used to record the
//!   basic blocks that we should branch to when a `continue` or `break` statement
//!   is encountered.
//! - **Custom scopes:** custom scopes are typically used to ensure cleanup
//!   of intermediate values.
//!
//! ### When to schedule cleanup
//!
//! Although the cleanup system is intended to *feel* fairly declarative,
//! it's still important to time calls to `schedule_clean()` correctly.
//! Basically, you should not schedule cleanup for memory until it has
//! been initialized, because if an unwind should occur before the memory
//! is fully initialized, then the cleanup will run and try to free or
//! drop uninitialized memory. If the initialization itself produces
//! byproducts that need to be freed, then you should use temporary custom
//! scopes to ensure that those byproducts will get freed on unwind.  For
//! example, an expression like `box foo()` will first allocate a box in the
//! heap and then call `foo()` -- if `foo()` should panic, this box needs
//! to be *shallowly* freed.
//!
//! ### Long-distance jumps
//!
//! In addition to popping a scope, which corresponds to normal control
//! flow exiting the scope, we may also *jump out* of a scope into some
//! earlier scope on the stack. This can occur in response to a `return`,
//! `break`, or `continue` statement, but also in response to panic. In
//! any of these cases, we will generate a series of cleanup blocks for
//! each of the scopes that is exited. So, if the stack contains scopes A
//! ... Z, and we break out of a loop whose corresponding cleanup scope is
//! X, we would generate cleanup blocks for the cleanups in X, Y, and Z.
//! After cleanup is done we would branch to the exit point for scope X.
//! But if panic should occur, we would generate cleanups for all the
//! scopes from A to Z and then resume the unwind process afterwards.
//!
//! To avoid generating tons of code, we cache the cleanup blocks that we
//! create for breaks, returns, unwinds, and other jumps. Whenever a new
//! cleanup is scheduled, though, we must clear these cached blocks. A
//! possible improvement would be to keep the cached blocks but simply
//! generate a new block which performs the additional cleanup and then
//! branches to the existing cached blocks.
//!
//! ### AST and loop cleanup scopes
//!
//! AST cleanup scopes are pushed when we begin and end processing an AST
//! node. They are used to house cleanups related to rvalue temporary that
//! get referenced (e.g., due to an expression like `&Foo()`). Whenever an
//! AST scope is popped, we always trans all the cleanups, adding the cleanup
//! code after the postdominator of the AST node.
//!
//! AST nodes that represent breakable loops also push a loop scope; the
//! loop scope never has any actual cleanups, it's just used to point to
//! the basic blocks where control should flow after a "continue" or
//! "break" statement. Popping a loop scope never generates code.
//!
//! ### Custom cleanup scopes
//!
//! Custom cleanup scopes are used for a variety of purposes. The most
//! common though is to handle temporary byproducts, where cleanup only
//! needs to occur on panic. The general strategy is to push a custom
//! cleanup scope, schedule *shallow* cleanups into the custom scope, and
//! then pop the custom scope (without transing the cleanups) when
//! execution succeeds normally. This way the cleanups are only trans'd on
//! unwind, and only up until the point where execution succeeded, at
//! which time the complete value should be stored in an lvalue or some
//! other place where normal cleanup applies.
//!
//! To spell it out, here is an example. Imagine an expression `box expr`.
//! We would basically:
//!
//! 1. Push a custom cleanup scope C.
//! 2. Allocate the box.
//! 3. Schedule a shallow free in the scope C.
//! 4. Trans `expr` into the box.
//! 5. Pop the scope C.
//! 6. Return the box as an rvalue.
//!
//! This way, if a panic occurs while transing `expr`, the custom
//! cleanup scope C is pushed and hence the box will be freed. The trans
//! code for `expr` itself is responsible for freeing any other byproducts
//! that may be in play.

use llvm::{BasicBlockRef, ValueRef};
use base::{self, Lifetime};
use common;
use common::{BlockAndBuilder, FunctionContext, Funclet};
use glue;
use type_::Type;
use value::Value;
use rustc::ty::Ty;

pub struct CleanupScope<'tcx> {
    // Cleanup to run upon scope exit.
    cleanup: DropValue<'tcx>,

    // Computed on creation if compiling with landing pads (!sess.no_landing_pads)
    pub landing_pad: Option<BasicBlockRef>,
}

#[derive(Copy, Clone, Debug)]
pub struct CustomScopeIndex {
    index: usize
}

#[derive(Copy, Clone, Debug)]
enum UnwindKind {
    LandingPad,
    CleanupPad(ValueRef),
}

impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
    pub fn trans_scope(
        &self,
        bcx: &BlockAndBuilder<'blk, 'tcx>,
        custom_scope: Option<CleanupScope<'tcx>>
    ) {
        if let Some(scope) = custom_scope {
            scope.cleanup.trans(bcx.funclet(), &bcx);
        }
    }

    /// Schedules a (deep) drop of `val`, which is a pointer to an instance of
    /// `ty`
    pub fn schedule_drop_mem(&self, val: ValueRef, ty: Ty<'tcx>) -> Option<CleanupScope<'tcx>> {
        if !self.type_needs_drop(ty) { return None; }
        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: false,
        };

        debug!("schedule_drop_mem(val={:?}, ty={:?}) skip_dtor={}", Value(val), ty, drop.skip_dtor);

        Some(CleanupScope::new(self, drop))
    }

    /// Issue #23611: Schedules a (deep) drop of the contents of
    /// `val`, which is a pointer to an instance of struct/enum type
    /// `ty`. The scheduled code handles extracting the discriminant
    /// and dropping the contents associated with that variant
    /// *without* executing any associated drop implementation.
    pub fn schedule_drop_adt_contents(&self, val: ValueRef, ty: Ty<'tcx>)
        -> Option<CleanupScope<'tcx>> {
        // `if` below could be "!contents_needs_drop"; skipping drop
        // is just an optimization, so sound to be conservative.
        if !self.type_needs_drop(ty) { return None; }

        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: true,
        };

        debug!("schedule_drop_adt_contents(val={:?}, ty={:?}) skip_dtor={}",
               Value(val),
               ty,
               drop.skip_dtor);

        Some(CleanupScope::new(self, drop))
    }

}

impl<'tcx> CleanupScope<'tcx> {
    fn new<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> {
        CleanupScope {
            cleanup: drop_val,
            landing_pad: if !fcx.ccx.sess().no_landing_pads() {
                Some(CleanupScope::get_landing_pad(fcx, &drop_val))
            } else {
                None
            },
        }
    }

    /// Creates a landing pad for the top scope, if one does not exist. The
    /// landing pad will perform all cleanups necessary for an unwind and then
    /// `resume` to continue error propagation:
    ///
    ///     landing_pad -> ... cleanups ... -> [resume]
    ///
    /// (The cleanups and resume instruction are created by
    /// `trans_cleanups_to_exit_scope()`, not in this function itself.)
    fn get_landing_pad<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: &DropValue<'tcx>)
        -> BasicBlockRef {
        debug!("get_landing_pad");

        let mut pad_bcx = fcx.build_new_block("unwind_custom_");

        let llpersonality = pad_bcx.fcx().eh_personality();

        let val = if base::wants_msvc_seh(fcx.ccx.sess()) {
            // A cleanup pad requires a personality function to be specified, so
            // we do that here explicitly (happens implicitly below through
            // creation of the landingpad instruction). We then create a
            // cleanuppad instruction which has no filters to run cleanup on all
            // exceptions.
            pad_bcx.set_personality_fn(llpersonality);
            let llretval = pad_bcx.cleanup_pad(None, &[]);
            UnwindKind::CleanupPad(llretval)
        } else {
            // The landing pad return type (the type being propagated). Not sure
            // what this represents but it's determined by the personality
            // function and this is what the EH proposal example uses.
            let llretty = Type::struct_(fcx.ccx,
                                        &[Type::i8p(fcx.ccx), Type::i32(fcx.ccx)],
                                        false);

            // The only landing pad clause will be 'cleanup'
            let llretval = pad_bcx.landing_pad(llretty, llpersonality, 1, pad_bcx.fcx().llfn);

            // The landing pad block is a cleanup
            pad_bcx.set_cleanup(llretval);

            let addr = match fcx.landingpad_alloca.get() {
                Some(addr) => addr,
                None => {
                    let addr = base::alloca(&pad_bcx, common::val_ty(llretval), "");
                    Lifetime::Start.call(&pad_bcx, addr);
                    fcx.landingpad_alloca.set(Some(addr));
                    addr
                }
            };
            pad_bcx.store(llretval, addr);
            UnwindKind::LandingPad
        };

        // Generate the cleanup block and branch to it.
        let cleanup_llbb = CleanupScope::trans_cleanups_to_exit_scope(fcx, val, drop_val);
        val.branch(&mut pad_bcx, cleanup_llbb);

        return pad_bcx.llbb();
    }

    /// Used when the caller wishes to jump to an early exit, such as a return,
    /// break, continue, or unwind. This function will generate all cleanups
    /// between the top of the stack and the exit `label` and return a basic
    /// block that the caller can branch to.
    fn trans_cleanups_to_exit_scope<'a>(
        fcx: &FunctionContext<'a, 'tcx>,
        label: UnwindKind,
        drop_val: &DropValue<'tcx>
    ) -> BasicBlockRef {
        debug!("trans_cleanups_to_exit_scope label={:?}`", label);

        // Generate a block that will resume unwinding to the calling function
        let bcx = fcx.build_new_block("resume");
        match label {
            UnwindKind::LandingPad => {
                let addr = fcx.landingpad_alloca.get().unwrap();
                let lp = bcx.load(addr);
                Lifetime::End.call(&bcx, addr);
                if !bcx.sess().target.target.options.custom_unwind_resume {
                    bcx.resume(lp);
                } else {
                    let exc_ptr = bcx.extract_value(lp, 0);
                    bcx.call(bcx.fcx().eh_unwind_resume().reify(bcx.ccx()), &[exc_ptr], None);
                }
            }
            UnwindKind::CleanupPad(_) => {
                bcx.cleanup_ret(bcx.cleanup_pad(None, &[]), None);
            }
        }

        let mut cleanup = fcx.build_new_block("clean_custom_");

        // Insert cleanup instructions into the cleanup block
        drop_val.trans(label.get_funclet(&cleanup).as_ref(), &cleanup);

        // Insert instruction into cleanup block to branch to the exit
        label.branch(&mut cleanup, bcx.llbb());

        debug!("trans_cleanups_to_exit_scope: llbb={:?}", cleanup.llbb());

        cleanup.llbb()
    }
}

impl UnwindKind {
    /// Generates a branch going from `bcx` to `to_llbb` where `self` is
    /// the exit label attached to the start of `bcx`.
    ///
    /// Transitions from an exit label to other exit labels depend on the type
    /// of label. For example with MSVC exceptions unwind exit labels will use
    /// the `cleanupret` instruction instead of the `br` instruction.
    fn branch(&self, bcx: &BlockAndBuilder, to_llbb: BasicBlockRef) {
        match *self {
            UnwindKind::CleanupPad(pad) => {
                bcx.cleanup_ret(pad, Some(to_llbb));
            }
            UnwindKind::LandingPad => {
                bcx.br(to_llbb);
            }
        }
    }

    fn get_funclet(&self, bcx: &BlockAndBuilder) -> Option<Funclet> {
        match *self {
            UnwindKind::CleanupPad(_) => {
                let pad = bcx.cleanup_pad(None, &[]);
                Funclet::msvc(pad)
            },
            UnwindKind::LandingPad => Funclet::gnu(),
        }
    }
}

impl PartialEq for UnwindKind {
    fn eq(&self, label: &UnwindKind) -> bool {
        match (*self, *label) {
            (UnwindKind::LandingPad, UnwindKind::LandingPad) |
            (UnwindKind::CleanupPad(..), UnwindKind::CleanupPad(..)) => true,
            _ => false,
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// Cleanup types

#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
    val: ValueRef,
    ty: Ty<'tcx>,
    skip_dtor: bool,
}

impl<'tcx> DropValue<'tcx> {
    fn trans<'blk>(&self, funclet: Option<&'blk Funclet>, bcx: &BlockAndBuilder<'blk, 'tcx>) {
        glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
    }
}
<commit_msg>Move around code in cleanup for a more logical ordering, and fix comments<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ## The Cleanup module
//!
//! The cleanup module tracks what values need to be cleaned up as scopes
//! are exited, either via panic or just normal control flow.
//!
//! Cleanup items can be scheduled into any of the scopes on the stack.
//! Typically, when a scope is finished, we generate the cleanup code. This
//! corresponds to a normal exit from a block (for example, an expression
//! completing evaluation successfully without panic).

use llvm::{BasicBlockRef, ValueRef};
use base::{self, Lifetime};
use common;
use common::{BlockAndBuilder, FunctionContext, Funclet};
use glue;
use type_::Type;
use value::Value;
use rustc::ty::Ty;

pub struct CleanupScope<'tcx> {
    // Cleanup to run upon scope exit.
    cleanup: DropValue<'tcx>,

    // Computed on creation if compiling with landing pads (!sess.no_landing_pads)
    pub landing_pad: Option<BasicBlockRef>,
}

#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
    val: ValueRef,
    ty: Ty<'tcx>,
    skip_dtor: bool,
}

impl<'tcx> DropValue<'tcx> {
    fn trans<'blk>(&self, funclet: Option<&'blk Funclet>, bcx: &BlockAndBuilder<'blk, 'tcx>) {
        glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
    }
}

#[derive(Copy, Clone, Debug)]
enum UnwindKind {
    LandingPad,
    CleanupPad(ValueRef),
}

impl UnwindKind {
    /// Generates a branch going from `bcx` to `to_llbb` where `self` is
    /// the exit label attached to the start of `bcx`.
    ///
    /// Transitions from an exit label to other exit labels depend on the type
    /// of label. For example with MSVC exceptions unwind exit labels will use
    /// the `cleanupret` instruction instead of the `br` instruction.
    fn branch(&self, bcx: &BlockAndBuilder, to_llbb: BasicBlockRef) {
        match *self {
            UnwindKind::CleanupPad(pad) => {
                bcx.cleanup_ret(pad, Some(to_llbb));
            }
            UnwindKind::LandingPad => {
                bcx.br(to_llbb);
            }
        }
    }

    fn get_funclet(&self, bcx: &BlockAndBuilder) -> Option<Funclet> {
        match *self {
            UnwindKind::CleanupPad(_) => {
                let pad = bcx.cleanup_pad(None, &[]);
                Funclet::msvc(pad)
            },
            UnwindKind::LandingPad => Funclet::gnu(),
        }
    }
}

impl PartialEq for UnwindKind {
    fn eq(&self, label: &UnwindKind) -> bool {
        match (*self, *label) {
            (UnwindKind::LandingPad, UnwindKind::LandingPad) |
            (UnwindKind::CleanupPad(..), UnwindKind::CleanupPad(..)) => true,
            _ => false,
        }
    }
}
impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
    pub fn trans_scope(
        &self,
        bcx: &BlockAndBuilder<'blk, 'tcx>,
        custom_scope: Option<CleanupScope<'tcx>>
    ) {
        if let Some(scope) = custom_scope {
            scope.cleanup.trans(bcx.funclet(), &bcx);
        }
    }

    /// Schedules a (deep) drop of `val`, which is a pointer to an instance of
    /// `ty`
    pub fn schedule_drop_mem(&self, val: ValueRef, ty: Ty<'tcx>) -> Option<CleanupScope<'tcx>> {
        if !self.type_needs_drop(ty) { return None; }
        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: false,
        };

        debug!("schedule_drop_mem(val={:?}, ty={:?}) skip_dtor={}", Value(val), ty, drop.skip_dtor);

        Some(CleanupScope::new(self, drop))
    }

    /// Issue #23611: Schedules a (deep) drop of the contents of
    /// `val`, which is a pointer to an instance of struct/enum type
    /// `ty`. The scheduled code handles extracting the discriminant
    /// and dropping the contents associated with that variant
    /// *without* executing any associated drop implementation.
    pub fn schedule_drop_adt_contents(&self, val: ValueRef, ty: Ty<'tcx>)
        -> Option<CleanupScope<'tcx>> {
        // `if` below could be "!contents_needs_drop"; skipping drop
        // is just an optimization, so sound to be conservative.
        if !self.type_needs_drop(ty) { return None; }

        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: true,
        };

        debug!("schedule_drop_adt_contents(val={:?}, ty={:?}) skip_dtor={}",
               Value(val), ty, drop.skip_dtor);

        Some(CleanupScope::new(self, drop))
    }

}

impl<'tcx> CleanupScope<'tcx> {
    fn new<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> {
        CleanupScope {
            cleanup: drop_val,
            landing_pad: if !fcx.ccx.sess().no_landing_pads() {
                Some(CleanupScope::get_landing_pad(fcx, &drop_val))
            } else {
                None
            },
        }
    }

    /// Creates a landing pad for the top scope, if one does not exist. The
    /// landing pad will perform all cleanups necessary for an unwind and then
    /// `resume` to continue error propagation:
    ///
    ///     landing_pad -> ... cleanups ... -> [resume]
    ///
    /// (The cleanups and resume instruction are created by
    /// `trans_cleanups_to_exit_scope()`, not in this function itself.)
    fn get_landing_pad<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: &DropValue<'tcx>)
        -> BasicBlockRef {
        debug!("get_landing_pad");

        let mut pad_bcx = fcx.build_new_block("unwind_custom_");

        let llpersonality = pad_bcx.fcx().eh_personality();

        let val = if base::wants_msvc_seh(fcx.ccx.sess()) {
            // A cleanup pad requires a personality function to be specified, so
            // we do that here explicitly (happens implicitly below through
            // creation of the landingpad instruction). We then create a
            // cleanuppad instruction which has no filters to run cleanup on all
            // exceptions.
            pad_bcx.set_personality_fn(llpersonality);
            let llretval = pad_bcx.cleanup_pad(None, &[]);
            UnwindKind::CleanupPad(llretval)
        } else {
            // The landing pad return type (the type being propagated). Not sure
            // what this represents but it's determined by the personality
            // function and this is what the EH proposal example uses.
            let llretty = Type::struct_(fcx.ccx,
                                        &[Type::i8p(fcx.ccx), Type::i32(fcx.ccx)],
                                        false);

            // The only landing pad clause will be 'cleanup'
            let llretval = pad_bcx.landing_pad(llretty, llpersonality, 1, pad_bcx.fcx().llfn);

            // The landing pad block is a cleanup
            pad_bcx.set_cleanup(llretval);

            let addr = match fcx.landingpad_alloca.get() {
                Some(addr) => addr,
                None => {
                    let addr = base::alloca(&pad_bcx, common::val_ty(llretval), "");
                    Lifetime::Start.call(&pad_bcx, addr);
                    fcx.landingpad_alloca.set(Some(addr));
                    addr
                }
            };
            pad_bcx.store(llretval, addr);
            UnwindKind::LandingPad
        };

        // Generate a block that will resume unwinding to the calling function
        let bcx = fcx.build_new_block("resume");
        match val {
            UnwindKind::LandingPad => {
                let addr = fcx.landingpad_alloca.get().unwrap();
                let lp = bcx.load(addr);
                Lifetime::End.call(&bcx, addr);
                if !bcx.sess().target.target.options.custom_unwind_resume {
                    bcx.resume(lp);
                } else {
                    let exc_ptr = bcx.extract_value(lp, 0);
                    bcx.call(bcx.fcx().eh_unwind_resume().reify(bcx.ccx()), &[exc_ptr], None);
                }
            }
            UnwindKind::CleanupPad(_) => {
                bcx.cleanup_ret(bcx.cleanup_pad(None, &[]), None);
            }
        }

        let mut cleanup = fcx.build_new_block("clean_custom_");

        // Insert cleanup instructions into the cleanup block
        drop_val.trans(val.get_funclet(&cleanup).as_ref(), &cleanup);

        // Insert instruction into cleanup block to branch to the exit
        val.branch(&mut cleanup, bcx.llbb());

        // Branch into the cleanup block
        val.branch(&mut pad_bcx, cleanup.llbb());

        return pad_bcx.llbb();
    }
}
<|endoftext|>


<commit_before><commit_msg>Update regex_cache.rs<commit_after><|endoftext|>


<commit_before><commit_msg>docs(examples): add an example using an HTTP/2 client<commit_after>#![deny(warnings)]
extern crate hyper;

extern crate env_logger;

use std::env;
use std::io;

use hyper::Client;
use hyper::header::Connection;
use hyper::http2;

fn main() {
    env_logger::init().unwrap();

    let url = match env::args().nth(1) {
        Some(url) => url,
        None => {
            println!("Usage: client <url>");
            return;
        }
    };

    let mut client = Client::with_protocol(http2::new_protocol());

    // `Connection: Close` is not a valid header for HTTP/2, but the client handles it gracefully.
    let mut res = client.get(&*url)
        .header(Connection::close())
        .send().unwrap();

    println!("Response: {}", res.status);
    println!("Headers:\n{}", res.headers);
    io::copy(&mut res, &mut io::stdout()).unwrap();
}
<|endoftext|>