<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use pango::ffi;
use libc::c_int;

/// The PangoGlyphString structure is used to store strings of glyphs with geometry and visual
/// attribute information. The storage for the glyph information is owned by the structure which
/// simplifies memory management.
#[repr(C)]
pub struct GlyphString {
    pointer: *mut ffi::C_PangoGlyphString
}

impl GlyphString {
    pub fn new() -> Option<GlyphString> {
        let tmp = unsafe { ffi::pango_glyph_string_new() };

        if tmp.is_null() {
            None
        } else {
            Some(GlyphString {
                pointer: tmp
            })
        }
    }

    pub fn copy(&self) -> Option<GlyphString> {
        let tmp = unsafe { ffi::pango_glyph_string_copy(self.pointer) };

        if tmp.is_null() {
            None
        } else {
            Some(GlyphString {
                pointer: tmp
            })
        }
    }

    pub fn set_size(&self, new_len: i32) {
        unsafe { ffi::pango_glyph_string_set_size(self.pointer, new_len as c_int) }
    }
}

impl Drop for GlyphString {
    fn drop(&mut self) {
        if pointer.is_null() {
            return;
        }
        unsafe { ffi::pango_glyph_string_free(self.pointer); }
        self.pointer = ::std::ptr::null_mut();
    }
}<commit_msg>Fix build error<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use pango::ffi;
use libc::c_int;

/// The PangoGlyphString structure is used to store strings of glyphs with geometry and visual
/// attribute information. The storage for the glyph information is owned by the structure which
/// simplifies memory management.
#[repr(C)]
pub struct GlyphString {
    pointer: *mut ffi::C_PangoGlyphString
}

impl GlyphString {
    pub fn new() -> Option<GlyphString> {
        let tmp = unsafe { ffi::pango_glyph_string_new() };

        if tmp.is_null() {
            None
        } else {
            Some(GlyphString {
                pointer: tmp
            })
        }
    }

    pub fn copy(&self) -> Option<GlyphString> {
        let tmp = unsafe { ffi::pango_glyph_string_copy(self.pointer) };

        if tmp.is_null() {
            None
        } else {
            Some(GlyphString {
                pointer: tmp
            })
        }
    }

    pub fn set_size(&self, new_len: i32) {
        unsafe { ffi::pango_glyph_string_set_size(self.pointer, new_len as c_int) }
    }
}

impl Drop for GlyphString {
    fn drop(&mut self) {
        if self.pointer.is_null() {
            return;
        }
        unsafe { ffi::pango_glyph_string_free(self.pointer); }
        self.pointer = ::std::ptr::null_mut();
    }
}<|endoftext|>


<commit_before><commit_msg>Simplify format_bar<commit_after><|endoftext|>


<commit_before>/*
src/renderer/shader.rs, 2017-08-13

Copyright (c) 2017 Juuso Tuononen

This file is licensed under

Apache License, Version 2.0

or

MIT License
*/

//! Shaders for `OpenGLRenderer`.
//!
//! Note that vertex shader's vertex attribute
//! variable indexes will be set in function `create_program`.
//! See function's documentation for more details.

use std::fs::File;
use std::io::Read;
use std::ffi::CString;

use gl::shader::*;
use gl::uniform::*;

use cgmath::{Matrix4, Vector3};

/// Render with texture. Supports OpenGL 3.3 and OpenGL ES 2.0.
pub struct TextureShader {
    program: Program,
    projection: UniformMatrix4,
    model: UniformMatrix4,
}

impl TextureShader {
    /// Creates new TextureShader
    ///
    /// # Panics
    /// If there is some error in creating the shader or uniforms.
    pub fn new() -> TextureShader {

        #[cfg(feature = "gles")]
        let program = create_program("src/shaders/gles/vertex-shader-gles.glsl", "src/shaders/gles/fragment-shader-gles.glsl");

        #[cfg(not(feature = "gles"))]
        let program = create_program("src/shaders/gl/vertex-shader.glsl", "src/shaders/gl/fragment-shader.glsl");

        let model = create_uniform("M", &program, "texture shader");
        let projection = create_uniform("P", &program, "texture shader");

        TextureShader { program, projection, model }
    }

    /// Sends uniform data specific to this shader to GPU.
    pub fn send_uniform_data(&mut self, model: &Matrix4<f32>, projection: &Matrix4<f32>) {
        self.model.send(model);
        self.projection.send(projection);
    }

    /// Tell OpenGL to use this shader program.
    pub fn use_program(&mut self) {
        self.program.use_program();
    }
}

/// Render tile map tiles. Supports OpenGL 3.3 and OpenGL ES 2.0.
pub struct TileMapShader {
    program: Program,
    projection: UniformMatrix4,
    model: UniformMatrix4,
    tile_position_change_x_y_and_scaling_factor: UniformVector3,
}

impl TileMapShader {
    /// Creates new TileMapShader
    ///
    /// # Panics
    /// If there is some error in creating the shader or uniforms.
    pub fn new() -> TileMapShader {

        #[cfg(feature = "gles")]
        let program = create_program("src/shaders/gles/vertex-shader-tilemap-gles.glsl", "src/shaders/gles/fragment-shader-tilemap-gles.glsl");

        #[cfg(not(feature = "gles"))]
        let program = create_program("src/shaders/gl/vertex-shader-tilemap.glsl", "src/shaders/gl/fragment-shader-tilemap.glsl");

        let model = create_uniform("M", &program, "tilemap shader");
        let projection = create_uniform("P", &program, "tilemap shader");
        let tile_position_change_x_y_and_scaling_factor = create_uniform("tile_info", &program, "tilemap shader");

        TileMapShader { program, projection, model, tile_position_change_x_y_and_scaling_factor }
    }

    /// Sends uniform data specific to this shader to GPU.
    pub fn send_uniform_data(&mut self, model: &Matrix4<f32>, projection: &Matrix4<f32>, tile_position_change_x_y_and_scaling_factor: &Vector3<f32>) {
        self.model.send(model);
        self.projection.send(projection);
        self.tile_position_change_x_y_and_scaling_factor.send(tile_position_change_x_y_and_scaling_factor);
    }

    /// Tell OpenGL to use this shader program.
    pub fn use_program(&mut self) {
        self.program.use_program();
    }
}

/// Render with specific color. Supports OpenGL 3.3 and OpenGL ES 2.0.
pub struct ColorShader {
    program: Program,
    projection: UniformMatrix4,
    model: UniformMatrix4,
    color: UniformVector3,
}

impl ColorShader {
    /// Creates new ColorShader
    ///
    /// # Panics
    /// If there is some error in creating the shader or uniforms.
    pub fn new() -> ColorShader {

        #[cfg(feature = "gles")]
        let program = create_program("src/shaders/gles/color-vertex-gles.glsl", "src/shaders/gles/color-fragment-gles.glsl");

        #[cfg(not(feature = "gles"))]
        let program = create_program("src/shaders/gl/color-vertex.glsl", "src/shaders/gl/color-fragment.glsl");

        let model = create_uniform("M", &program, "color shader");
        let projection = create_uniform("P", &program, "color shader");
        let color = create_uniform("color", &program, "color shader");

        ColorShader { program, projection, model, color }
    }

    /// Sends uniform data specific to this shader to GPU.
    pub fn send_uniform_data(&mut self, model: &Matrix4<f32>, projection: &Matrix4<f32>, color: &Vector3<f32>) {
        self.model.send(model);
        self.projection.send(projection);
        self.color.send(color);
    }

    /// Tell OpenGL to use this shader program.
    pub fn use_program(&mut self) {
        self.program.use_program();
    }
}

/// Build shader program from file paths.
///
/// # Panics
/// * If there is error opening or reading the files.
/// * There is error compiling or linking the shaders.
/// * Shader code contains 0 byte.
///
/// # Vertex attribute variable indexes
/// * variable "vertex", index 0
/// * variable "texture_coordinates_attribute", index 1
///
fn create_program(vertex_shader_path: &str, fragment_shader_path: &str) -> Program {
    let vertex_shader = load_shader(ShaderType::Vertex, vertex_shader_path);
    let fragment_shader = load_shader(ShaderType::Fragment, fragment_shader_path);

    let mut vertex_attributes = VertexAttributeIndexBinder::new();
    vertex_attributes.add_attribute(0, "vertex");
    vertex_attributes.add_attribute(1, "texture_coordinates_attribute");

    match Program::new(vertex_shader, fragment_shader, vertex_attributes) {
        Ok(program) => program,
        Err(message) => {
            println!("program creation error:\n{}", message);
            panic!();
        }
    }
}

/// Read shader source code from file and create shader of type `ShaderType`.
///
/// # Panics
/// * If there is error opening or reading the files.
/// * There is error compiling the shader.
/// * Shader code contains 0 byte.
fn load_shader(shader_type: ShaderType, file_path: &str) -> Shader {
    let mut shader_file = File::open(file_path).expect("shader file not found");
    let mut shader_text = String::new();

    shader_file.read_to_string(&mut shader_text).unwrap();

    let shader_text = CString::new(shader_text).unwrap();

    match Shader::new(shader_type, shader_text) {
        Ok(shader) => shader,
        Err(message) => {
            println!("shader compile error\n{}", message);
            panic!();
        },
    }
}

/// Create uniform specific to one shader program.
///
/// `program_name` argument is for displaying program name in the possible error message.
///
/// # Panics
/// * If `name` argument contains 0 byte.
/// * If there is not uniform with name that equals argument `name` in the shader program.
fn create_uniform<T: Uniform>(name: &str, program: &Program, program_name: &str) -> T {
    let uniform_result = T::new(CString::new(name).unwrap(), &program);

    match uniform_result {
        Ok(uniform) => uniform,
        Err(error) => {
            println!("error: {:?}\n uniform name: {}\n program name: {}\n", error, name, program_name);
            panic!();
        },
    }
}<commit_msg>include shader source codes in program binary file<commit_after>/*
src/renderer/shader.rs, 2017-09-02

Copyright (c) 2017 Juuso Tuononen

This file is licensed under

Apache License, Version 2.0

or

MIT License
*/

//! Shaders for `OpenGLRenderer`.
//!
//! Note that vertex shader's vertex attribute
//! variable indexes will be set in function `create_program`.
//! See function's documentation for more details.

use std::ffi::CString;

use gl::shader::*;
use gl::uniform::*;

use cgmath::{Matrix4, Vector3};

/// Render with texture. Supports OpenGL 3.3 and OpenGL ES 2.0.
pub struct TextureShader {
    program: Program,
    projection: UniformMatrix4,
    model: UniformMatrix4,
}

impl TextureShader {
    /// Creates new TextureShader
    ///
    /// # Panics
    /// If there is some error in creating the shader or uniforms.
    pub fn new() -> TextureShader {

        #[cfg(feature = "gles")]
        let program = create_program(include_str!("../shaders/gles/vertex-shader-gles.glsl"), include_str!("../shaders/gles/fragment-shader-gles.glsl"));

        #[cfg(not(feature = "gles"))]
        let program = create_program(include_str!("../shaders/gl/vertex-shader.glsl"), include_str!("../shaders/gl/fragment-shader.glsl"));

        let model = create_uniform("M", &program, "texture shader");
        let projection = create_uniform("P", &program, "texture shader");

        TextureShader { program, projection, model }
    }

    /// Sends uniform data specific to this shader to GPU.
    pub fn send_uniform_data(&mut self, model: &Matrix4<f32>, projection: &Matrix4<f32>) {
        self.model.send(model);
        self.projection.send(projection);
    }

    /// Tell OpenGL to use this shader program.
    pub fn use_program(&mut self) {
        self.program.use_program();
    }
}

/// Render tile map tiles. Supports OpenGL 3.3 and OpenGL ES 2.0.
pub struct TileMapShader {
    program: Program,
    projection: UniformMatrix4,
    model: UniformMatrix4,
    tile_position_change_x_y_and_scaling_factor: UniformVector3,
}

impl TileMapShader {
    /// Creates new TileMapShader
    ///
    /// # Panics
    /// If there is some error in creating the shader or uniforms.
    pub fn new() -> TileMapShader {

        #[cfg(feature = "gles")]
        let program = create_program(include_str!("../shaders/gles/vertex-shader-tilemap-gles.glsl"), include_str!("../shaders/gles/fragment-shader-tilemap-gles.glsl"));

        #[cfg(not(feature = "gles"))]
        let program = create_program(include_str!("../shaders/gl/vertex-shader-tilemap.glsl"), include_str!("../shaders/gl/fragment-shader-tilemap.glsl"));

        let model = create_uniform("M", &program, "tilemap shader");
        let projection = create_uniform("P", &program, "tilemap shader");
        let tile_position_change_x_y_and_scaling_factor = create_uniform("tile_info", &program, "tilemap shader");

        TileMapShader { program, projection, model, tile_position_change_x_y_and_scaling_factor }
    }

    /// Sends uniform data specific to this shader to GPU.
    pub fn send_uniform_data(&mut self, model: &Matrix4<f32>, projection: &Matrix4<f32>, tile_position_change_x_y_and_scaling_factor: &Vector3<f32>) {
        self.model.send(model);
        self.projection.send(projection);
        self.tile_position_change_x_y_and_scaling_factor.send(tile_position_change_x_y_and_scaling_factor);
    }

    /// Tell OpenGL to use this shader program.
    pub fn use_program(&mut self) {
        self.program.use_program();
    }
}

/// Render with specific color. Supports OpenGL 3.3 and OpenGL ES 2.0.
pub struct ColorShader {
    program: Program,
    projection: UniformMatrix4,
    model: UniformMatrix4,
    color: UniformVector3,
}

impl ColorShader {
    /// Creates new ColorShader
    ///
    /// # Panics
    /// If there is some error in creating the shader or uniforms.
    pub fn new() -> ColorShader {

        #[cfg(feature = "gles")]
        let program = create_program(include_str!("../shaders/gles/color-vertex-gles.glsl"), include_str!("../shaders/gles/color-fragment-gles.glsl"));

        #[cfg(not(feature = "gles"))]
        let program = create_program(include_str!("../shaders/gl/color-vertex.glsl"), include_str!("../shaders/gl/color-fragment.glsl"));

        let model = create_uniform("M", &program, "color shader");
        let projection = create_uniform("P", &program, "color shader");
        let color = create_uniform("color", &program, "color shader");

        ColorShader { program, projection, model, color }
    }

    /// Sends uniform data specific to this shader to GPU.
    pub fn send_uniform_data(&mut self, model: &Matrix4<f32>, projection: &Matrix4<f32>, color: &Vector3<f32>) {
        self.model.send(model);
        self.projection.send(projection);
        self.color.send(color);
    }

    /// Tell OpenGL to use this shader program.
    pub fn use_program(&mut self) {
        self.program.use_program();
    }
}

/// Build shader program from source code string slices.
///
/// # Panics
/// * There is error compiling or linking the shaders.
/// * Shader code contains 0 byte.
///
/// # Vertex attribute variable indexes
/// * variable "vertex", index 0
/// * variable "texture_coordinates_attribute", index 1
///
fn create_program(vertex_shader_code: &str, fragment_shader_code: &str) -> Program {
    let vertex_shader = load_shader(ShaderType::Vertex, vertex_shader_code);
    let fragment_shader = load_shader(ShaderType::Fragment, fragment_shader_code);

    let mut vertex_attributes = VertexAttributeIndexBinder::new();
    vertex_attributes.add_attribute(0, "vertex");
    vertex_attributes.add_attribute(1, "texture_coordinates_attribute");

    match Program::new(vertex_shader, fragment_shader, vertex_attributes) {
        Ok(program) => program,
        Err(message) => {
            println!("program creation error:\n{}", message);
            panic!();
        }
    }
}

/// Create shader of type `ShaderType` from shader source code.
///
/// # Panics
/// * There is error compiling the shader.
/// * Shader code contains 0 byte.
fn load_shader(shader_type: ShaderType, source_code: &str) -> Shader {
    let shader_text = CString::new(source_code).unwrap();

    match Shader::new(shader_type, shader_text) {
        Ok(shader) => shader,
        Err(message) => {
            println!("shader compile error\n{}", message);
            panic!();
        },
    }
}

/// Create uniform specific to one shader program.
///
/// `program_name` argument is for displaying program name in the possible error message.
///
/// # Panics
/// * If `name` argument contains 0 byte.
/// * If there is not uniform with name that equals argument `name` in the shader program.
fn create_uniform<T: Uniform>(name: &str, program: &Program, program_name: &str) -> T {
    let uniform_result = T::new(CString::new(name).unwrap(), &program);

    match uniform_result {
        Ok(uniform) => uniform,
        Err(error) => {
            println!("error: {:?}\n uniform name: {}\n program name: {}\n", error, name, program_name);
            panic!();
        },
    }
}<|endoftext|>


<commit_before>use crate::common::Config;
use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;

use tracing::*;

#[cfg(test)]
mod tests;

/// Conversion table from triple OS name to Rust SYSNAME
const OS_TABLE: &[(&str, &str)] = &[
    ("android", "android"),
    ("androideabi", "android"),
    ("cuda", "cuda"),
    ("darwin", "macos"),
    ("dragonfly", "dragonfly"),
    ("emscripten", "emscripten"),
    ("freebsd", "freebsd"),
    ("fuchsia", "fuchsia"),
    ("haiku", "haiku"),
    ("hermit", "hermit"),
    ("illumos", "illumos"),
    ("ios", "ios"),
    ("l4re", "l4re"),
    ("linux", "linux"),
    ("mingw32", "windows"),
    ("none", "none"),
    ("netbsd", "netbsd"),
    ("openbsd", "openbsd"),
    ("redox", "redox"),
    ("sgx", "sgx"),
    ("solaris", "solaris"),
    ("win32", "windows"),
    ("windows", "windows"),
    ("vxworks", "vxworks"),
];

const ARCH_TABLE: &[(&str, &str)] = &[
    ("aarch64", "aarch64"),
    ("aarch64_be", "aarch64"),
    ("amd64", "x86_64"),
    ("arm", "arm"),
    ("arm64", "aarch64"),
    ("armv4t", "arm"),
    ("armv5te", "arm"),
    ("armv7", "arm"),
    ("armv7s", "arm"),
    ("asmjs", "asmjs"),
    ("avr", "avr"),
    ("bpfeb", "bpf"),
    ("bpfel", "bpf"),
    ("hexagon", "hexagon"),
    ("i386", "x86"),
    ("i586", "x86"),
    ("i686", "x86"),
    ("mips", "mips"),
    ("mips64", "mips64"),
    ("mips64el", "mips64"),
    ("mipsisa32r6", "mips"),
    ("mipsisa32r6el", "mips"),
    ("mipsisa64r6", "mips64"),
    ("mipsisa64r6el", "mips64"),
    ("mipsel", "mips"),
    ("mipsisa32r6", "mips"),
    ("mipsisa32r6el", "mips"),
    ("mipsisa64r6", "mips64"),
    ("mipsisa64r6el", "mips64"),
    ("msp430", "msp430"),
    ("nvptx64", "nvptx64"),
    ("powerpc", "powerpc"),
    ("powerpc64", "powerpc64"),
    ("powerpc64le", "powerpc64"),
    ("riscv64gc", "riscv64"),
    ("s390x", "s390x"),
    ("sparc", "sparc"),
    ("sparc64", "sparc64"),
    ("sparcv9", "sparc64"),
    ("thumbv6m", "thumb"),
    ("thumbv7em", "thumb"),
    ("thumbv7m", "thumb"),
    ("wasm32", "wasm32"),
    ("x86_64", "x86_64"),
    ("xcore", "xcore"),
];

pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
    "aarch64-apple-darwin",
    "aarch64-fuchsia",
    "aarch64-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-fuchsia",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
];

pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
    "aarch64-apple-darwin",
    "aarch64-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-unknown-linux-gnu",
];

pub const MSAN_SUPPORTED_TARGETS: &[&str] =
    &["aarch64-unknown-linux-gnu", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu"];

pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
    "aarch64-apple-darwin",
    "aarch64-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
];

pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
    &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];

const BIG_ENDIAN: &[&str] = &[
    "aarch64_be",
    "armebv7r",
    "mips",
    "mips64",
    "mipsisa32r6",
    "mipsisa64r6",
    "powerpc",
    "powerpc64",
    "s390x",
    "sparc",
    "sparc64",
    "sparcv9",
];

static ASM_SUPPORTED_ARCHS: &[&str] = &[
    "x86", "x86_64", "arm", "aarch64", "riscv32", "riscv64", "nvptx64", "hexagon", "mips",
    "mips64", "spirv", "wasm32",
];

pub fn has_asm_support(triple: &str) -> bool {
    ASM_SUPPORTED_ARCHS.contains(&get_arch(triple))
}

pub fn matches_os(triple: &str, name: &str) -> bool {
    // For the wasm32 bare target we ignore anything also ignored on emscripten
    // and then we also recognize `wasm32-bare` as the os for the target
    if triple == "wasm32-unknown-unknown" {
        return name == "emscripten" || name == "wasm32-bare";
    }
    let triple: Vec<_> = triple.split('-').collect();
    for &(triple_os, os) in OS_TABLE {
        if triple.contains(&triple_os) {
            return os == name;
        }
    }
    panic!("Cannot determine OS from triple");
}

/// Determine the architecture from `triple`
pub fn get_arch(triple: &str) -> &'static str {
    let triple: Vec<_> = triple.split('-').collect();
    for &(triple_arch, arch) in ARCH_TABLE {
        if triple.contains(&triple_arch) {
            return arch;
        }
    }
    panic!("Cannot determine Architecture from triple");
}

/// Determine the endianness from `triple`
pub fn is_big_endian(triple: &str) -> bool {
    let triple_arch = triple.split('-').next().unwrap();
    BIG_ENDIAN.contains(&triple_arch)
}

pub fn matches_env(triple: &str, name: &str) -> bool {
    if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
}

pub fn get_pointer_width(triple: &str) -> &'static str {
    if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32"))
        || triple.starts_with("s390x")
    {
        "64bit"
    } else if triple.starts_with("avr") {
        "16bit"
    } else {
        "32bit"
    }
}

pub fn make_new_path(path: &str) -> String {
    assert!(cfg!(windows));
    // Windows just uses PATH as the library search path, so we have to
    // maintain the current value while adding our own
    match env::var(lib_path_env_var()) {
        Ok(curr) => format!("{}{}{}", path, path_div(), curr),
        Err(..) => path.to_owned(),
    }
}

pub fn lib_path_env_var() -> &'static str {
    "PATH"
}
fn path_div() -> &'static str {
    ";"
}

pub fn logv(config: &Config, s: String) {
    debug!("{}", s);
    if config.verbose {
        println!("{}", s);
    }
}

pub trait PathBufExt {
    /// Append an extension to the path, even if it already has one.
    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
}

impl PathBufExt for PathBuf {
    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
        if extension.as_ref().is_empty() {
            self.clone()
        } else {
            let mut fname = self.file_name().unwrap().to_os_string();
            if !extension.as_ref().to_str().unwrap().starts_with('.') {
                fname.push(".");
            }
            fname.push(extension);
            self.with_file_name(fname)
        }
    }
}
<commit_msg>compiletest: Add m68k to ARCH_TABLE<commit_after>use crate::common::Config;
use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;

use tracing::*;

#[cfg(test)]
mod tests;

/// Conversion table from triple OS name to Rust SYSNAME
const OS_TABLE: &[(&str, &str)] = &[
    ("android", "android"),
    ("androideabi", "android"),
    ("cuda", "cuda"),
    ("darwin", "macos"),
    ("dragonfly", "dragonfly"),
    ("emscripten", "emscripten"),
    ("freebsd", "freebsd"),
    ("fuchsia", "fuchsia"),
    ("haiku", "haiku"),
    ("hermit", "hermit"),
    ("illumos", "illumos"),
    ("ios", "ios"),
    ("l4re", "l4re"),
    ("linux", "linux"),
    ("mingw32", "windows"),
    ("none", "none"),
    ("netbsd", "netbsd"),
    ("openbsd", "openbsd"),
    ("redox", "redox"),
    ("sgx", "sgx"),
    ("solaris", "solaris"),
    ("win32", "windows"),
    ("windows", "windows"),
    ("vxworks", "vxworks"),
];

const ARCH_TABLE: &[(&str, &str)] = &[
    ("aarch64", "aarch64"),
    ("aarch64_be", "aarch64"),
    ("amd64", "x86_64"),
    ("arm", "arm"),
    ("arm64", "aarch64"),
    ("armv4t", "arm"),
    ("armv5te", "arm"),
    ("armv7", "arm"),
    ("armv7s", "arm"),
    ("asmjs", "asmjs"),
    ("avr", "avr"),
    ("bpfeb", "bpf"),
    ("bpfel", "bpf"),
    ("hexagon", "hexagon"),
    ("i386", "x86"),
    ("i586", "x86"),
    ("i686", "x86"),
    ("m68k", "m68k"),
    ("mips", "mips"),
    ("mips64", "mips64"),
    ("mips64el", "mips64"),
    ("mipsisa32r6", "mips"),
    ("mipsisa32r6el", "mips"),
    ("mipsisa64r6", "mips64"),
    ("mipsisa64r6el", "mips64"),
    ("mipsel", "mips"),
    ("mipsisa32r6", "mips"),
    ("mipsisa32r6el", "mips"),
    ("mipsisa64r6", "mips64"),
    ("mipsisa64r6el", "mips64"),
    ("msp430", "msp430"),
    ("nvptx64", "nvptx64"),
    ("powerpc", "powerpc"),
    ("powerpc64", "powerpc64"),
    ("powerpc64le", "powerpc64"),
    ("riscv64gc", "riscv64"),
    ("s390x", "s390x"),
    ("sparc", "sparc"),
    ("sparc64", "sparc64"),
    ("sparcv9", "sparc64"),
    ("thumbv6m", "thumb"),
    ("thumbv7em", "thumb"),
    ("thumbv7m", "thumb"),
    ("wasm32", "wasm32"),
    ("x86_64", "x86_64"),
    ("xcore", "xcore"),
];

pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
    "aarch64-apple-darwin",
    "aarch64-fuchsia",
    "aarch64-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-fuchsia",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
];

pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
    "aarch64-apple-darwin",
    "aarch64-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-unknown-linux-gnu",
];

pub const MSAN_SUPPORTED_TARGETS: &[&str] =
    &["aarch64-unknown-linux-gnu", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu"];

pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
    "aarch64-apple-darwin",
    "aarch64-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-unknown-freebsd",
    "x86_64-unknown-linux-gnu",
];

pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
    &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];

const BIG_ENDIAN: &[&str] = &[
    "aarch64_be",
    "armebv7r",
    "mips",
    "mips64",
    "mipsisa32r6",
    "mipsisa64r6",
    "powerpc",
    "powerpc64",
    "s390x",
    "sparc",
    "sparc64",
    "sparcv9",
];

static ASM_SUPPORTED_ARCHS: &[&str] = &[
    "x86", "x86_64", "arm", "aarch64", "riscv32", "riscv64", "nvptx64", "hexagon", "mips",
    "mips64", "spirv", "wasm32",
];

pub fn has_asm_support(triple: &str) -> bool {
    ASM_SUPPORTED_ARCHS.contains(&get_arch(triple))
}

pub fn matches_os(triple: &str, name: &str) -> bool {
    // For the wasm32 bare target we ignore anything also ignored on emscripten
    // and then we also recognize `wasm32-bare` as the os for the target
    if triple == "wasm32-unknown-unknown" {
        return name == "emscripten" || name == "wasm32-bare";
    }
    let triple: Vec<_> = triple.split('-').collect();
    for &(triple_os, os) in OS_TABLE {
        if triple.contains(&triple_os) {
            return os == name;
        }
    }
    panic!("Cannot determine OS from triple");
}

/// Determine the architecture from `triple`
pub fn get_arch(triple: &str) -> &'static str {
    let triple: Vec<_> = triple.split('-').collect();
    for &(triple_arch, arch) in ARCH_TABLE {
        if triple.contains(&triple_arch) {
            return arch;
        }
    }
    panic!("Cannot determine Architecture from triple");
}

/// Determine the endianness from `triple`
pub fn is_big_endian(triple: &str) -> bool {
    let triple_arch = triple.split('-').next().unwrap();
    BIG_ENDIAN.contains(&triple_arch)
}

pub fn matches_env(triple: &str, name: &str) -> bool {
    if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
}

pub fn get_pointer_width(triple: &str) -> &'static str {
    if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32"))
        || triple.starts_with("s390x")
    {
        "64bit"
    } else if triple.starts_with("avr") {
        "16bit"
    } else {
        "32bit"
    }
}

pub fn make_new_path(path: &str) -> String {
    assert!(cfg!(windows));
    // Windows just uses PATH as the library search path, so we have to
    // maintain the current value while adding our own
    match env::var(lib_path_env_var()) {
        Ok(curr) => format!("{}{}{}", path, path_div(), curr),
        Err(..) => path.to_owned(),
    }
}

pub fn lib_path_env_var() -> &'static str {
    "PATH"
}
fn path_div() -> &'static str {
    ";"
}

pub fn logv(config: &Config, s: String) {
    debug!("{}", s);
    if config.verbose {
        println!("{}", s);
    }
}

pub trait PathBufExt {
    /// Append an extension to the path, even if it already has one.
    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
}

impl PathBufExt for PathBuf {
    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
        if extension.as_ref().is_empty() {
            self.clone()
        } else {
            let mut fname = self.file_name().unwrap().to_os_string();
            if !extension.as_ref().to_str().unwrap().starts_with('.') {
                fname.push(".");
            }
            fname.push(extension);
            self.with_file_name(fname)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Builds a `RenderPass` object whose template parameter is of undeterminate type.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        $device:expr,
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}
        }
    ) => (
        ordered_passes_renderpass!(
            $device,
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: []
                }
            ]
        )
    )
}

/// Builds a `RenderPass` object whose template parameter is of undeterminate type.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        $device:expr,
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:expr,
                    samples: $samples:expr,
                    $(initial_layout: $init_layout:expr,)*
                    $(final_layout: $final_layout:expr,)*
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]
                }
            ),*
        ]
    ) => ({
        use $crate::framebuffer::RenderPassDesc;

        mod scope {
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]

            use $crate::format::ClearValue;
            use $crate::format::Format;
            use $crate::framebuffer::RenderPassDesc;
            use $crate::framebuffer::RenderPassDescClearValues;
            use $crate::framebuffer::LayoutAttachmentDescription;
            use $crate::framebuffer::LayoutPassDescription;
            use $crate::framebuffer::LayoutPassDependencyDescription;
            use $crate::image::ImageLayout;
            use $crate::sync::AccessFlagBits;
            use $crate::sync::PipelineStages;

            pub struct CustomRenderPassDesc {
                $(
                    pub $atch_name: (Format, u32),
                )*
            }

            #[allow(unsafe_code)]
            unsafe impl RenderPassDesc for CustomRenderPassDesc {
                #[inline]
                fn num_attachments(&self) -> usize {
                    num_attachments()
                }

                #[inline]
                fn attachment_desc(&self, id: usize) -> Option<LayoutAttachmentDescription> {
                    attachment(self, id)
                }

                #[inline]
                fn num_subpasses(&self) -> usize {
                    num_subpasses()
                }

                #[inline]
                fn subpass_desc(&self, id: usize) -> Option<LayoutPassDescription> {
                    subpass(id)
                }

                #[inline]
                fn num_dependencies(&self) -> usize {
                    num_dependencies()
                }

                #[inline]
                fn dependency_desc(&self, id: usize) -> Option<LayoutPassDependencyDescription> {
                    dependency(id)
                }
            }

            unsafe impl RenderPassDescClearValues<Vec<ClearValue>> for CustomRenderPassDesc {
                fn convert_clear_values(&self, values: Vec<ClearValue>) -> Box<Iterator<Item = ClearValue>> {
                    // FIXME: safety checks
                    Box::new(values.into_iter())
                }
            }

            #[inline]
            fn num_attachments() -> usize {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]
                let mut num = 0;
                $(let $atch_name = num; num += 1;)*
                num
            }

            #[inline]
            fn attachment(desc: &CustomRenderPassDesc, id: usize) -> Option<LayoutAttachmentDescription> {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]

                let mut num = 0;

                $({
                    if id == num {
                        let (initial_layout, final_layout) = attachment_layouts(num);

                        return Some($crate::framebuffer::LayoutAttachmentDescription {
                            format: desc.$atch_name.0,
                            samples: desc.$atch_name.1,
                            load: $crate::framebuffer::LoadOp::$load,
                            store: $crate::framebuffer::StoreOp::$store,
                            stencil_load: $crate::framebuffer::LoadOp::$load,
                            stencil_store: $crate::framebuffer::StoreOp::$store,
                            initial_layout: initial_layout,
                            final_layout: final_layout,
                        });
                    }

                    num += 1;
                })*

                None
            }

            #[inline]
            fn num_subpasses() -> usize {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]
                let mut num = 0;
                $($(let $color_atch = num;)* num += 1;)*
                num
            }

            #[inline]
            fn subpass(id: usize) -> Option<LayoutPassDescription> {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]

                let mut attachment_num = 0;
                $(
                    let $atch_name = attachment_num;
                    attachment_num += 1;
                )*

                let mut cur_pass_num = 0;

                $({
                    if id == cur_pass_num {
                        let mut depth = None;
                        $(
                            depth = Some(($depth_atch, ImageLayout::DepthStencilAttachmentOptimal));
                        )*

                        return Some(LayoutPassDescription {
                            color_attachments: vec![
                                $(
                                    ($color_atch, ImageLayout::ColorAttachmentOptimal)
                                ),*
                            ],
                            depth_stencil: depth,
                            input_attachments: vec![
                                $(
                                    ($input_atch, ImageLayout::ShaderReadOnlyOptimal)
                                ),*
                            ],
                            resolve_attachments: vec![],
                            preserve_attachments: (0 .. attachment_num).filter(|&a| {
                                $(if a == $color_atch { return false; })*
                                $(if a == $depth_atch { return false; })*
                                $(if a == $input_atch { return false; })*
                                true
                            }).collect()
                        });
                    }

                    cur_pass_num += 1;
                })*

                None
            }

            #[inline]
            fn num_dependencies() -> usize {
                num_subpasses().saturating_sub(1)
            }

            #[inline]
            fn dependency(id: usize) -> Option<LayoutPassDependencyDescription> {
                let num_passes = num_subpasses();

                if id + 1 >= num_passes {
                    return None;
                }

                Some(LayoutPassDependencyDescription {
                    source_subpass: id,
                    destination_subpass: id + 1,
                    source_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                    destination_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                    source_access: AccessFlagBits::all(),         // TODO: correct values
                    destination_access: AccessFlagBits::all(),         // TODO: correct values
                    by_region: true,            // TODO: correct values
                })
            }

            /// Returns the initial and final layout of an attachment, given its num.
            ///
            /// The value always correspond to the first and last usages of an attachment.
            fn attachment_layouts(num: usize) -> (ImageLayout, ImageLayout) {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]

                let mut attachment_num = 0;
                $(
                    let $atch_name = attachment_num;
                    attachment_num += 1;
                )*

                let mut initial_layout = None;
                let mut final_layout = None;

                $({
                    $(
                        if $depth_atch == num {
                            if initial_layout.is_none() {
                                initial_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
                            }
                            final_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
                        }
                    )*

                    $(
                        if $color_atch == num {
                            if initial_layout.is_none() {
                                initial_layout = Some(ImageLayout::ColorAttachmentOptimal);
                            }
                            final_layout = Some(ImageLayout::ColorAttachmentOptimal);
                        }
                    )*

                    $(
                        if $input_atch == num {
                            if initial_layout.is_none() {
                                initial_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
                            }
                            final_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
                        }
                    )*
                })*

                $(if $atch_name == num {
                    // If the clear OP is Clear or DontCare, default to the Undefined layout.
                    if initial_layout == Some(ImageLayout::DepthStencilAttachmentOptimal) ||
                        initial_layout == Some(ImageLayout::ColorAttachmentOptimal)
                    {
                        if $crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::Clear ||
                            $crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::DontCare
                        {
                            initial_layout = Some(ImageLayout::Undefined);
                        }
                    }

                    $(initial_layout = Some($init_layout);)*
                    $(final_layout = Some($final_layout);)*
                })*

                (initial_layout.unwrap(), final_layout.unwrap())
            }
        }

        scope::CustomRenderPassDesc {
            $(
                $atch_name: ($format, $samples),
            )*
        }.build_render_pass($device)
    });
}
<commit_msg>Add `resolve` to ordered_passes_renderpass! (#727)<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Builds a `RenderPass` object whose template parameter is of undeterminate type.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        $device:expr,
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}
        }
    ) => (
        ordered_passes_renderpass!(
            $device,
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: []
                }
            ]
        )
    )
}

/// Builds a `RenderPass` object whose template parameter is of undeterminate type.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        $device:expr,
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:expr,
                    samples: $samples:expr,
                    $(initial_layout: $init_layout:expr,)*
                    $(final_layout: $final_layout:expr,)*
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]$(,)*
                    $(resolve: [$($resolve_atch:ident),*])*$(,)*
                }
            ),*
        ]
    ) => ({
        use $crate::framebuffer::RenderPassDesc;

        mod scope {
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]

            use $crate::format::ClearValue;
            use $crate::format::Format;
            use $crate::framebuffer::RenderPassDesc;
            use $crate::framebuffer::RenderPassDescClearValues;
            use $crate::framebuffer::LayoutAttachmentDescription;
            use $crate::framebuffer::LayoutPassDescription;
            use $crate::framebuffer::LayoutPassDependencyDescription;
            use $crate::image::ImageLayout;
            use $crate::sync::AccessFlagBits;
            use $crate::sync::PipelineStages;

            pub struct CustomRenderPassDesc {
                $(
                    pub $atch_name: (Format, u32),
                )*
            }

            #[allow(unsafe_code)]
            unsafe impl RenderPassDesc for CustomRenderPassDesc {
                #[inline]
                fn num_attachments(&self) -> usize {
                    num_attachments()
                }

                #[inline]
                fn attachment_desc(&self, id: usize) -> Option<LayoutAttachmentDescription> {
                    attachment(self, id)
                }

                #[inline]
                fn num_subpasses(&self) -> usize {
                    num_subpasses()
                }

                #[inline]
                fn subpass_desc(&self, id: usize) -> Option<LayoutPassDescription> {
                    subpass(id)
                }

                #[inline]
                fn num_dependencies(&self) -> usize {
                    num_dependencies()
                }

                #[inline]
                fn dependency_desc(&self, id: usize) -> Option<LayoutPassDependencyDescription> {
                    dependency(id)
                }
            }

            unsafe impl RenderPassDescClearValues<Vec<ClearValue>> for CustomRenderPassDesc {
                fn convert_clear_values(&self, values: Vec<ClearValue>) -> Box<Iterator<Item = ClearValue>> {
                    // FIXME: safety checks
                    Box::new(values.into_iter())
                }
            }

            #[inline]
            fn num_attachments() -> usize {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]
                let mut num = 0;
                $(let $atch_name = num; num += 1;)*
                num
            }

            #[inline]
            fn attachment(desc: &CustomRenderPassDesc, id: usize) -> Option<LayoutAttachmentDescription> {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]

                let mut num = 0;

                $({
                    if id == num {
                        let (initial_layout, final_layout) = attachment_layouts(num);

                        return Some($crate::framebuffer::LayoutAttachmentDescription {
                            format: desc.$atch_name.0,
                            samples: desc.$atch_name.1,
                            load: $crate::framebuffer::LoadOp::$load,
                            store: $crate::framebuffer::StoreOp::$store,
                            stencil_load: $crate::framebuffer::LoadOp::$load,
                            stencil_store: $crate::framebuffer::StoreOp::$store,
                            initial_layout: initial_layout,
                            final_layout: final_layout,
                        });
                    }

                    num += 1;
                })*

                None
            }

            #[inline]
            fn num_subpasses() -> usize {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]
                let mut num = 0;
                $($(let $color_atch = num;)* num += 1;)*
                num
            }

            #[inline]
            fn subpass(id: usize) -> Option<LayoutPassDescription> {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]

                let mut attachment_num = 0;
                $(
                    let $atch_name = attachment_num;
                    attachment_num += 1;
                )*

                let mut cur_pass_num = 0;

                $({
                    if id == cur_pass_num {
                        let mut depth = None;
                        $(
                            depth = Some(($depth_atch, ImageLayout::DepthStencilAttachmentOptimal));
                        )*

                        let mut desc = LayoutPassDescription {
                            color_attachments: vec![
                                $(
                                    ($color_atch, ImageLayout::ColorAttachmentOptimal)
                                ),*
                            ],
                            depth_stencil: depth,
                            input_attachments: vec![
                                $(
                                    ($input_atch, ImageLayout::ShaderReadOnlyOptimal)
                                ),*
                            ],
                            resolve_attachments: vec![
                                $(
                                    ($resolve_atch, ImageLayout::TransferDstOptimal)
                                ),*
                            ],
                            preserve_attachments: (0 .. attachment_num).filter(|&a| {
                                $(if a == $color_atch { return false; })*
                                $(if a == $depth_atch { return false; })*
                                $(if a == $input_atch { return false; })*
                                true
                            }).collect()
                        };

                        assert!(desc.resolve_attachments.is_empty() ||
                                desc.resolve_attachments.len() == desc.color_attachments.len());
                        return Some(desc);
                    }

                    cur_pass_num += 1;
                })*

                None
            }

            #[inline]
            fn num_dependencies() -> usize {
                num_subpasses().saturating_sub(1)
            }

            #[inline]
            fn dependency(id: usize) -> Option<LayoutPassDependencyDescription> {
                let num_passes = num_subpasses();

                if id + 1 >= num_passes {
                    return None;
                }

                Some(LayoutPassDependencyDescription {
                    source_subpass: id,
                    destination_subpass: id + 1,
                    source_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                    destination_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                    source_access: AccessFlagBits::all(),         // TODO: correct values
                    destination_access: AccessFlagBits::all(),         // TODO: correct values
                    by_region: true,            // TODO: correct values
                })
            }

            /// Returns the initial and final layout of an attachment, given its num.
            ///
            /// The value always correspond to the first and last usages of an attachment.
            fn attachment_layouts(num: usize) -> (ImageLayout, ImageLayout) {
                #![allow(unused_assignments)]
                #![allow(unused_mut)]
                #![allow(unused_variables)]

                let mut attachment_num = 0;
                $(
                    let $atch_name = attachment_num;
                    attachment_num += 1;
                )*

                let mut initial_layout = None;
                let mut final_layout = None;

                $({
                    $(
                        if $depth_atch == num {
                            if initial_layout.is_none() {
                                initial_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
                            }
                            final_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
                        }
                    )*

                    $(
                        if $color_atch == num {
                            if initial_layout.is_none() {
                                initial_layout = Some(ImageLayout::ColorAttachmentOptimal);
                            }
                            final_layout = Some(ImageLayout::ColorAttachmentOptimal);
                        }
                    )*

                    $(
                        if $resolve_atch == num {
                            if initial_layout.is_none() {
                                initial_layout = Some(ImageLayout::TransferDstOptimal);
                            }
                            final_layout = Some(ImageLayout::TransferDstOptimal);
                        }
                    )*

                    $(
                        if $input_atch == num {
                            if initial_layout.is_none() {
                                initial_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
                            }
                            final_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
                        }
                    )*
                })*

                $(if $atch_name == num {
                    // If the clear OP is Clear or DontCare, default to the Undefined layout.
                    if initial_layout == Some(ImageLayout::DepthStencilAttachmentOptimal) ||
                        initial_layout == Some(ImageLayout::ColorAttachmentOptimal) ||
                        initial_layout == Some(ImageLayout::TransferDstOptimal)
                    {
                        if $crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::Clear ||
                            $crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::DontCare
                        {
                            initial_layout = Some(ImageLayout::Undefined);
                        }
                    }

                    $(initial_layout = Some($init_layout);)*
                    $(final_layout = Some($final_layout);)*
                })*

                (initial_layout.unwrap(), final_layout.unwrap())
            }
        }

        scope::CustomRenderPassDesc {
            $(
                $atch_name: ($format, $samples),
            )*
        }.build_render_pass($device)
    });
}
<|endoftext|>


<commit_before>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char(rd: &mut MemReader) -> char {
  match rd.read_byte() {
    Some(b) => b as char,
    None => fail!()
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>)
}

// parse values recursivly
fn parse_value(rd: &mut MemReader) -> Value {
    enum State {
        st_value,
        st_number,
        st_got_number
    }

    let mut state: State = st_value;
    let mut val: ~str = ~"";

    loop {
        match state {
            st_value => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '0' .. '9' => {
                        val.push_char(ch);
                        state = st_number;
                    }
                    't' => {
                        assert!(read_char(rd) == 'r');
                        assert!(read_char(rd) == 'u');
                        assert!(read_char(rd) == 'e');
                        return True
                    }
                    'f' => {
                        assert!(read_char(rd) == 'a');
                        assert!(read_char(rd) == 'l');
                        assert!(read_char(rd) == 's');
                        assert!(read_char(rd) == 'e');
                        return False
                    }
                    '"' => {
                        loop {
                            let ch = read_char(rd);
                            if ch == '"' {
                                break;
                            }
                            val.push_char(ch);
                        }
                        return String(val)
                    }
                    _ => { fail!() }
                }
            }
            st_got_number => {
                return Unsigned(from_str(val).unwrap())
            }
            st_number => {
                if rd.eof() {
                    state = st_got_number;
                } else {
                    let ch = read_char(rd);
                    match ch {
                        '\r' | '\n' | ' ' | '\t' => { state = st_got_number }
                        '#' => { skip_comment(rd); state = st_got_number }
                        '0' .. '9' => {
                            val.push_char(ch);
                        }
                        _ => { fail!() }
                    }
                }
            }
        }
    }
}

// We must be already within the '#"
fn skip_comment(rd: &mut MemReader) {
    loop {
        if rd.eof() { return }
        match read_char(rd) {
            '\n' => { return }
            _ => { }
        }
    }
}

fn parse(rd: &mut MemReader) -> HashMap<~str, Value> {
    enum State {
        st_toplevel,
        st_comment,
        st_section,
        st_ident,
        st_assign_wanted,
        st_value_wanted
    }

    let mut state = st_toplevel;
    let mut buf: ~str = ~"";
    let mut path: ~str = ~"";

    let mut root = HashMap::new();

    loop {
        match state {
            st_toplevel => {
                if rd.eof() { break }
                let ch = read_char(rd);
                match ch {
                    // ignore whitespace
                    '\r' | '\n' | ' ' | '\t' => { }

                    // comment
                    '#' => { state = st_comment }

                    // section
                    '[' => { state = st_section }

                    // identifier
                    'a' .. 'z' | 'A' .. 'Z' | '_' => {
                        state = st_ident;
                        buf.push_char(ch)
                    }

                    _ => { fail!() }
                }
            }
            st_comment => {
                if rd.eof() { break }
                match read_char(rd) {
                    '\n' => { state = st_toplevel }
                    _ => { }
                }
            }
            st_section => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                    }
                    ']' => {
                        debug!("Section: {}", buf);
                        path = buf.clone();
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { fail!() }
                }
            }
            st_ident => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_'=> {
                        buf.push_char(ch);
                    }

                    '\r' | '\n' | ' ' | '\t' => { state = st_assign_wanted }

                    '=' => { state = st_value_wanted }

                    _ => { fail!() }
                }
            }
            st_assign_wanted => {
                if rd.eof() { fail!() }
                match read_char(rd) {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '=' => { state = st_value_wanted }
                    _ => { fail!() }
                }
            }
            st_value_wanted => {
                debug!("Key: {}", buf);
                let val = parse_value(rd);

                debug!("Value: {:?}", val);
                debug!("Path: {}", path);

                // XXX: split path
                let mut m = root.find_or_insert(path.clone(), Map(HashMap::new())); // XXX: remove clone
                match *m {
                    Map(ref mut map) => {
                        let fresh = map.insert(buf.clone(), val);
                        assert!(fresh == true);
                    }
                    _ => { fail!("Invalid TOML") }
                }

                buf.truncate(0);
                state = st_toplevel;
            }
        }
    }

    return root;
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let root = parse(&mut rd);
  println!("{:s}", root.to_str());
}
<commit_msg>Factor building up of data structure out of parser<commit_after>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char(rd: &mut MemReader) -> char {
  match rd.read_byte() {
    Some(b) => b as char,
    None => fail!()
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

// parse values recursivly
fn parse_value(rd: &mut MemReader) -> Value {
    enum State {
        st_value,
        st_number,
        st_got_number
    }

    let mut state: State = st_value;
    let mut val: ~str = ~"";

    loop {
        match state {
            st_value => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '0' .. '9' => {
                        val.push_char(ch);
                        state = st_number;
                    }
                    't' => {
                        assert!(read_char(rd) == 'r');
                        assert!(read_char(rd) == 'u');
                        assert!(read_char(rd) == 'e');
                        return True
                    }
                    'f' => {
                        assert!(read_char(rd) == 'a');
                        assert!(read_char(rd) == 'l');
                        assert!(read_char(rd) == 's');
                        assert!(read_char(rd) == 'e');
                        return False
                    }
                    '"' => {
                        loop {
                            let ch = read_char(rd);
                            if ch == '"' {
                                break;
                            }
                            val.push_char(ch);
                        }
                        return String(val)
                    }
                    _ => { fail!() }
                }
            }
            st_got_number => {
                return Unsigned(from_str(val).unwrap())
            }
            st_number => {
                if rd.eof() {
                    state = st_got_number;
                } else {
                    let ch = read_char(rd);
                    match ch {
                        '\r' | '\n' | ' ' | '\t' => { state = st_got_number }
                        '#' => { skip_comment(rd); state = st_got_number }
                        '0' .. '9' => {
                            val.push_char(ch);
                        }
                        _ => { fail!() }
                    }
                }
            }
        }
    }
}

// We must be already within the '#"
fn skip_comment(rd: &mut MemReader) {
    loop {
        if rd.eof() { return }
        match read_char(rd) {
            '\n' => { return }
            _ => { }
        }
    }
}

trait Visitor {
    fn section(&mut self, name: &str, is_array: bool);
    fn pair(&mut self, key: &str, val: Value);
}

struct MyVisitor {
    root: HashMap<~str, Value>,
    current_path: ~str
}

impl MyVisitor {
    fn new() -> MyVisitor {
        MyVisitor { root: HashMap::new(), current_path: ~"" }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for MyVisitor {
    fn section(&mut self, name: &str, is_array: bool) {
        assert!(is_array == false);
        debug!("Section: {}", name);
        self.current_path = name.to_owned(); //clone();
    }
    fn pair(&mut self, key: &str, val: Value) {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_path.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let fresh = map.insert(key.to_owned(), val);
                assert!(fresh == true);
            }
            _ => { fail!("Invalid TOML") }
        }
    }
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) {
    enum State {
        st_toplevel,
        st_comment,
        st_section,
        st_ident,
        st_assign_wanted,
        st_value_wanted
    }

    let mut state = st_toplevel;
    let mut buf: ~str = ~"";

    loop {
        match state {
            st_toplevel => {
                if rd.eof() { break }
                let ch = read_char(rd);
                match ch {
                    // ignore whitespace
                    '\r' | '\n' | ' ' | '\t' => { }

                    // comment
                    '#' => { state = st_comment }

                    // section
                    '[' => { state = st_section }

                    // identifier
                    'a' .. 'z' | 'A' .. 'Z' | '_' => {
                        state = st_ident;
                        buf.push_char(ch)
                    }

                    _ => { fail!() }
                }
            }
            st_comment => {
                if rd.eof() { break }
                match read_char(rd) {
                    '\n' => { state = st_toplevel }
                    _ => { }
                }
            }
            st_section => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                    }
                    ']' => {
                        visitor.section(buf, false);
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { fail!() }
                }
            }
            st_ident => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_'=> {
                        buf.push_char(ch);
                    }

                    '\r' | '\n' | ' ' | '\t' => { state = st_assign_wanted }

                    '=' => { state = st_value_wanted }

                    _ => { fail!() }
                }
            }
            st_assign_wanted => {
                if rd.eof() { fail!() }
                match read_char(rd) {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '=' => { state = st_value_wanted }
                    _ => { fail!() }
                }
            }
            st_value_wanted => {
                visitor.pair(buf, parse_value(rd));
                buf.truncate(0);
                state = st_toplevel;
            }
        }
    }
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = MyVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<|endoftext|>


<commit_before>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char(rd: &mut MemReader) -> char {
  match rd.read_byte() {
    Some(b) => b as char,
    None => fail!()
  }
}

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

// parse values recursivly
fn parse_value(rd: &mut MemReader) -> Value {
    enum State {
        st_value,
        st_number,
        st_got_number
    }

    let mut state: State = st_value;
    let mut val: ~str = ~"";

    loop {
        match state {
            st_value => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '0' .. '9' => {
                        val.push_char(ch);
                        state = st_number;
                    }
                    't' => {
                        assert!(read_char(rd) == 'r');
                        assert!(read_char(rd) == 'u');
                        assert!(read_char(rd) == 'e');
                        return True
                    }
                    'f' => {
                        assert!(read_char(rd) == 'a');
                        assert!(read_char(rd) == 'l');
                        assert!(read_char(rd) == 's');
                        assert!(read_char(rd) == 'e');
                        return False
                    }
                    '"' => {
                        loop {
                            let ch = read_char(rd);
                            if ch == '"' {
                                break;
                            }
                            val.push_char(ch);
                        }
                        return String(val)
                    }
                    _ => { fail!() }
                }
            }
            st_got_number => {
                return Unsigned(from_str(val).unwrap())
            }
            st_number => {
                if rd.eof() {
                    state = st_got_number;
                } else {
                    let ch = read_char(rd);
                    match ch {
                        '\r' | '\n' | ' ' | '\t' => { state = st_got_number }
                        '#' => { skip_comment(rd); state = st_got_number }
                        '0' .. '9' => {
                            val.push_char(ch);
                        }
                        _ => { fail!() }
                    }
                }
            }
        }
    }
}

// We must be already within the '#"
fn skip_comment(rd: &mut MemReader) {
    loop {
        if rd.eof() { return }
        match read_char(rd) {
            '\n' => { return }
            _ => { }
        }
    }
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: &str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_path: ~str,
    is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_path: ~"", is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.is_array = is_array;
        self.current_path = name;
        return true
    }
    fn pair(&mut self, key: &str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_path.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key.to_owned(), val);
                return ok
            }
            _ => { return false }
        }
    }
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) -> bool {
    enum State {
        st_toplevel,
        st_ident,
        st_assign_wanted,
        st_value_wanted
    }

    let mut state = st_toplevel;
    let mut buf: ~str = ~"";

    let mut current_char: Option<char> = read_char_opt(rd);

    loop {
        match state {
            st_toplevel => {
                if current_char.is_none() { return true }
                let ch = current_char.unwrap();
                match ch {
                    // ignore whitespace
                    '\r' | '\n' | ' ' | '\t' => { }

                    // comment
                    '#' => {
                        // skip to end of line
                        loop {
                            current_char = read_char_opt(rd);
                            match current_char {
                                Some('\n') => { break }
                                None => { return true }
                                _ => { /* skip */ }
                            }
                        }
                    }

                    // section
                    '[' => {
                        current_char = read_char_opt(rd); // advance
                        let mut double_section = false;
                        match current_char {
                            Some('[') => {
                                double_section = true;
                                current_char = read_char_opt(rd); // advance
                            }
                            _ => {}
                        }
                        let mut section = ~"";
                        loop {
                            if current_char.is_none() { return false }
                            let ch = current_char.unwrap();
                            match ch {
                                'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                                    section.push_char(ch);
                                }
                                ']' => {
                                    break
                                }
                                _ => { return false }
                            }
                            current_char = read_char_opt(rd); // advance
                        }

                        assert!(current_char == Some(']'));

                        if double_section {
                            current_char = read_char_opt(rd); // advance
                            if current_char != Some(']') { return false }
                        }

                        visitor.section(section, double_section);
                    }

                    // identifier
                    'a' .. 'z' | 'A' .. 'Z' | '_' => {
                        state = st_ident;
                        buf.push_char(ch)
                    }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_ident => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_'=> {
                        buf.push_char(ch);
                    }

                    '\r' | '\n' | ' ' | '\t' => { state = st_assign_wanted }

                    '=' => { state = st_value_wanted }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_assign_wanted => {
                if current_char.is_none() { return false }
                match current_char.unwrap() {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '=' => { state = st_value_wanted }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_value_wanted => {
                visitor.pair(buf, parse_value(rd));
                buf.truncate(0);
                state = st_toplevel;
                current_char = read_char_opt(rd); // advance
            }
        }
    }

    assert!(false);
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = TOMLVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<commit_msg>Factor out section identifier parsing<commit_after>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char(rd: &mut MemReader) -> char {
  match rd.read_byte() {
    Some(b) => b as char,
    None => fail!()
  }
}

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

// parse values recursivly
fn parse_value(rd: &mut MemReader) -> Value {
    enum State {
        st_value,
        st_number,
        st_got_number
    }

    let mut state: State = st_value;
    let mut val: ~str = ~"";

    loop {
        match state {
            st_value => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '0' .. '9' => {
                        val.push_char(ch);
                        state = st_number;
                    }
                    't' => {
                        assert!(read_char(rd) == 'r');
                        assert!(read_char(rd) == 'u');
                        assert!(read_char(rd) == 'e');
                        return True
                    }
                    'f' => {
                        assert!(read_char(rd) == 'a');
                        assert!(read_char(rd) == 'l');
                        assert!(read_char(rd) == 's');
                        assert!(read_char(rd) == 'e');
                        return False
                    }
                    '"' => {
                        loop {
                            let ch = read_char(rd);
                            if ch == '"' {
                                break;
                            }
                            val.push_char(ch);
                        }
                        return String(val)
                    }
                    _ => { fail!() }
                }
            }
            st_got_number => {
                return Unsigned(from_str(val).unwrap())
            }
            st_number => {
                if rd.eof() {
                    state = st_got_number;
                } else {
                    let ch = read_char(rd);
                    match ch {
                        '\r' | '\n' | ' ' | '\t' => { state = st_got_number }
                        '#' => { skip_comment(rd); state = st_got_number }
                        '0' .. '9' => {
                            val.push_char(ch);
                        }
                        _ => { fail!() }
                    }
                }
            }
        }
    }
}

// We must be already within the '#"
fn skip_comment(rd: &mut MemReader) {
    loop {
        if rd.eof() { return }
        match read_char(rd) {
            '\n' => { return }
            _ => { }
        }
    }
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: &str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_path: ~str,
    is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_path: ~"", is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.is_array = is_array;
        self.current_path = name;
        return true
    }
    fn pair(&mut self, key: &str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_path.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key.to_owned(), val);
                return ok
            }
            _ => { return false }
        }
    }
}

fn parse_section_identifier(rd: &mut MemReader, current_char: Option<char>) -> (~str, Option<char>) {
    let mut current_char = current_char;
    let mut section_name = ~"";
    loop {
        match current_char {
            Some(ch) => {
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        section_name.push_char(ch);
                    }
                    _ => { break }
                }
            }
            None => { break }
        }
        current_char = read_char_opt(rd); // advance
    }

    return (section_name, current_char);
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) -> bool {
    enum State {
        st_toplevel,
        st_ident,
        st_assign_wanted,
        st_value_wanted
    }

    let mut state = st_toplevel;
    let mut buf: ~str = ~"";

    let mut current_char: Option<char> = read_char_opt(rd);

    loop {
        match state {
            st_toplevel => {
                if current_char.is_none() { return true }
                let ch = current_char.unwrap();
                match ch {
                    // ignore whitespace
                    '\r' | '\n' | ' ' | '\t' => { }

                    // comment
                    '#' => {
                        // skip to end of line
                        loop {
                            current_char = read_char_opt(rd);
                            match current_char {
                                Some('\n') => { break }
                                None => { return true }
                                _ => { /* skip */ }
                            }
                        }
                    }

                    // section
                    '[' => {
                        current_char = read_char_opt(rd); // advance
                        let mut double_section = false;
                        match current_char {
                            Some('[') => {
                                double_section = true;
                                current_char = read_char_opt(rd); // advance
                            }
                            _ => {}
                        }

                        let (section_name, ch) = parse_section_identifier(rd, current_char);
                        current_char = ch;

                        match current_char {
                            Some(']') => { /* ok */ }
                            _ => { return false }
                        }

                        if double_section {
                            current_char = read_char_opt(rd); // advance
                            if current_char != Some(']') { return false }
                        }

                        visitor.section(section_name, double_section);
                    }

                    // identifier
                    'a' .. 'z' | 'A' .. 'Z' | '_' => {
                        state = st_ident;
                        buf.push_char(ch)
                    }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_ident => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_'=> {
                        buf.push_char(ch);
                    }

                    '\r' | '\n' | ' ' | '\t' => { state = st_assign_wanted }

                    '=' => { state = st_value_wanted }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_assign_wanted => {
                if current_char.is_none() { return false }
                match current_char.unwrap() {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '=' => { state = st_value_wanted }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_value_wanted => {
                visitor.pair(buf, parse_value(rd));
                buf.truncate(0);
                state = st_toplevel;
                current_char = read_char_opt(rd); // advance
            }
        }
    }

    assert!(false);
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = TOMLVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<|endoftext|>