<commit_before>//! Common utilities for the generator and the build script for Qt crates.
//!
//!
//! See [README](https://github.com/rust-qt/cpp_to_rust)
//! for more information.

use log::debug;
use ritual_common::cpp_build_config::{
    CppBuildConfig, CppBuildConfigData, CppBuildPaths, CppLibraryType,
};
use ritual_common::errors::{bail, Result};
use ritual_common::string_utils::CaseOperations;
use ritual_common::target;
use ritual_common::utils::get_command_output;
use std::path::PathBuf;
use std::process::Command;

/// Makes a query to `qmake`.
fn run_qmake_string_query(property: &str) -> Result<String> {
    let result = get_command_output(Command::new("qmake").arg("-query").arg(property))?;
    Ok(result.trim().to_string())
}

/// Makes a query to `qmake` and interprets its output as a path.
fn run_qmake_query(property: &str) -> Result<PathBuf> {
    Ok(PathBuf::from(run_qmake_string_query(property)?))
}

/// Properties of a Qt installation
pub struct InstallationData {
    /// Qt version.
    pub qt_version: String,
    /// Path to the parent include directory of the installation.
    pub root_include_path: PathBuf,
    /// Path to the include directory of the library that is being processed.
    /// This is a direct subdirectory of `root_include_path`.
    pub lib_include_path: PathBuf,
    /// Path to the directory containing library files for the linker.
    pub lib_path: PathBuf,
    /// Path to the directory containing Qt documentation files.
    pub docs_path: PathBuf,
    /// If true, this Qt library was built as a MacOS framework.
    pub is_framework: bool,
}

/// Detects properties of current Qt installation using `qmake` command line utility.
pub fn get_installation_data(crate_name: &str) -> Result<InstallationData> {
    let qt_version = run_qmake_string_query("QT_VERSION")?;
    debug!("QT_VERSION = \"{}\"", qt_version);
    debug!("Detecting Qt directories");

    let root_include_path = run_qmake_query("QT_INSTALL_HEADERS")?;
    debug!("QT_INSTALL_HEADERS = \"{}\"", root_include_path.display());
    let lib_path = run_qmake_query("QT_INSTALL_LIBS")?;
    debug!("QT_INSTALL_LIBS = \"{}\"", lib_path.display());
    let docs_path = run_qmake_query("QT_INSTALL_DOCS")?;
    debug!("QT_INSTALL_DOCS = \"{}\"", docs_path.display());
    let folder_name = lib_folder_name(crate_name);
    let dir = root_include_path.join(&folder_name);
    if dir.exists() {
        Ok(InstallationData {
            root_include_path,
            lib_path,
            docs_path,
            lib_include_path: dir,
            is_framework: false,
            qt_version,
        })
    } else {
        let dir2 = lib_path.join(format!("{}.framework/Headers", folder_name));
        if dir2.exists() {
            Ok(InstallationData {
                root_include_path,
                lib_path,
                docs_path,
                lib_include_path: dir2,
                is_framework: true,
                qt_version,
            })
        } else {
            bail!(
                "extra header dir not found (tried: {}, {})",
                dir.display(),
                dir2.display()
            );
        }
    }
}

pub struct FullBuildConfig {
    pub installation_data: InstallationData,
    pub cpp_build_config: CppBuildConfig,
    pub cpp_build_paths: CppBuildPaths,
}

pub fn get_full_build_config(crate_name: &str) -> Result<FullBuildConfig> {
    let installation_data = get_installation_data(crate_name)?;
    let mut cpp_build_paths = CppBuildPaths::new();
    let mut cpp_build_config_data = CppBuildConfigData::new();
    {
        let mut apply_installation_data = |name: &str, data: &InstallationData| {
            cpp_build_paths.add_include_path(&data.root_include_path);
            cpp_build_paths.add_include_path(&data.lib_include_path);
            if data.is_framework {
                cpp_build_paths.add_framework_path(&data.lib_path);
                cpp_build_config_data.add_linked_framework(framework_name(name));
            } else {
                cpp_build_paths.add_lib_path(&data.lib_path);
                cpp_build_config_data.add_linked_lib(real_lib_name(name));
            }
        };

        apply_installation_data(crate_name, &installation_data);
        for dep in lib_dependencies(crate_name)? {
            let dep_data = get_installation_data(dep)?;
            apply_installation_data(dep, &dep_data);
        }
    }
    let mut cpp_build_config = CppBuildConfig::new();
    cpp_build_config.add(target::Condition::True, cpp_build_config_data);
    {
        let mut data = CppBuildConfigData::new();
        data.add_compiler_flag("-std=gnu++11");
        cpp_build_config.add(target::Condition::Env(target::Env::Msvc).negate(), data);
    }
    {
        let mut data = CppBuildConfigData::new();
        data.add_compiler_flag("-fPIC");
        // msvc and mingw don't need this
        cpp_build_config.add(target::Condition::OS(target::OS::Windows).negate(), data);
    }
    {
        let mut data = CppBuildConfigData::new();
        data.set_library_type(CppLibraryType::Shared);
        cpp_build_config.add(target::Condition::Env(target::Env::Msvc), data);
    }
    Ok(FullBuildConfig {
        installation_data,
        cpp_build_config,
        cpp_build_paths,
    })
}

/// Returns library name of the specified module as
/// should be passed to the linker, e.g. `"Qt5Core"`.
pub fn real_lib_name(crate_name: &str) -> String {
    let sublib_name = crate_name.replace("qt_", "");
    let sublib_name_capitalized = sublib_name.to_class_case();
    format!("Qt5{}", sublib_name_capitalized)
}

/// Returns name of the module's include directory, e.g. `"QtCore"`.
pub fn lib_folder_name(crate_name: &str) -> String {
    let sublib_name = crate_name.replace("qt_", "");
    let sublib_name_capitalized = sublib_name.to_class_case();
    format!("Qt{}", sublib_name_capitalized)
}

/// Returns MacOS framework name of the specified module as
/// should be passed to the linker, e.g. `"QtCore"`.
pub fn framework_name(crate_name: &str) -> String {
    let sublib_name = crate_name.replace("qt_", "");
    let sublib_name_capitalized = sublib_name.to_class_case();
    format!("Qt{}", sublib_name_capitalized)
}

pub fn all_crate_names() -> &'static [&'static str] {
    &[
        "qt_core",
        "qt_gui",
        "qt_widgets",
        "qt_ui_tools",
        "qt_3d_core",
        "qt_3d_render",
        "qt_3d_input",
        "qt_3d_logic",
        "qt_3d_extras",
    ]
}

/// Returns list of modules this module depends on.
pub fn lib_dependencies(crate_name: &str) -> Result<&'static [&'static str]> {
    const CORE: &[&str] = &[];
    const GUI: &[&str] = &["qt_core"];
    const WIDGETS: &[&str] = &["qt_core", "qt_gui"];
    const UI_TOOLS: &[&str] = &["qt_core", "qt_gui", "qt_widgets"];
    const CORE3D: &[&str] = &["qt_core", "qt_gui"];
    const RENDER3D: &[&str] = &["qt_core", "qt_gui", "qt_3d_core"];
    const INPUT3D: &[&str] = &["qt_core", "qt_gui", "qt_3d_core"];
    const LOGIC3D: &[&str] = &["qt_core", "qt_gui", "qt_3d_core"];
    const EXTRAS3D: &[&str] = &[
        "qt_core",
        "qt_gui",
        "qt_3d_core",
        "qt_3d_render",
        "qt_3d_input",
        "qt_3d_logic",
    ];
    const MOQT_CORE: &[&str] = &[];
    Ok(match crate_name {
        "qt_core" => CORE,
        "qt_gui" => GUI,
        "qt_widgets" => WIDGETS,
        "qt_3d_core" => CORE3D,
        "qt_3d_render" => RENDER3D,
        "qt_3d_input" => INPUT3D,
        "qt_3d_logic" => LOGIC3D,
        "qt_3d_extras" => EXTRAS3D,
        "qt_ui_tools" => UI_TOOLS,
        "moqt_core" => MOQT_CORE,
        _ => bail!("Unknown crate name: {}", crate_name),
    })
}
<commit_msg>Refactoring: simplify lib_dependencies() code<commit_after>//! Common utilities for the generator and the build script for Qt crates.
//!
//!
//! See [README](https://github.com/rust-qt/cpp_to_rust)
//! for more information.

use log::debug;
use ritual_common::cpp_build_config::{
    CppBuildConfig, CppBuildConfigData, CppBuildPaths, CppLibraryType,
};
use ritual_common::errors::{bail, Result};
use ritual_common::string_utils::CaseOperations;
use ritual_common::target;
use ritual_common::utils::get_command_output;
use std::path::PathBuf;
use std::process::Command;

/// Makes a query to `qmake`.
fn run_qmake_string_query(property: &str) -> Result<String> {
    let result = get_command_output(Command::new("qmake").arg("-query").arg(property))?;
    Ok(result.trim().to_string())
}

/// Makes a query to `qmake` and interprets its output as a path.
fn run_qmake_query(property: &str) -> Result<PathBuf> {
    Ok(PathBuf::from(run_qmake_string_query(property)?))
}

/// Properties of a Qt installation
pub struct InstallationData {
    /// Qt version.
    pub qt_version: String,
    /// Path to the parent include directory of the installation.
    pub root_include_path: PathBuf,
    /// Path to the include directory of the library that is being processed.
    /// This is a direct subdirectory of `root_include_path`.
    pub lib_include_path: PathBuf,
    /// Path to the directory containing library files for the linker.
    pub lib_path: PathBuf,
    /// Path to the directory containing Qt documentation files.
    pub docs_path: PathBuf,
    /// If true, this Qt library was built as a MacOS framework.
    pub is_framework: bool,
}

/// Detects properties of current Qt installation using `qmake` command line utility.
pub fn get_installation_data(crate_name: &str) -> Result<InstallationData> {
    let qt_version = run_qmake_string_query("QT_VERSION")?;
    debug!("QT_VERSION = \"{}\"", qt_version);
    debug!("Detecting Qt directories");

    let root_include_path = run_qmake_query("QT_INSTALL_HEADERS")?;
    debug!("QT_INSTALL_HEADERS = \"{}\"", root_include_path.display());
    let lib_path = run_qmake_query("QT_INSTALL_LIBS")?;
    debug!("QT_INSTALL_LIBS = \"{}\"", lib_path.display());
    let docs_path = run_qmake_query("QT_INSTALL_DOCS")?;
    debug!("QT_INSTALL_DOCS = \"{}\"", docs_path.display());
    let folder_name = lib_folder_name(crate_name);
    let dir = root_include_path.join(&folder_name);
    if dir.exists() {
        Ok(InstallationData {
            root_include_path,
            lib_path,
            docs_path,
            lib_include_path: dir,
            is_framework: false,
            qt_version,
        })
    } else {
        let dir2 = lib_path.join(format!("{}.framework/Headers", folder_name));
        if dir2.exists() {
            Ok(InstallationData {
                root_include_path,
                lib_path,
                docs_path,
                lib_include_path: dir2,
                is_framework: true,
                qt_version,
            })
        } else {
            bail!(
                "extra header dir not found (tried: {}, {})",
                dir.display(),
                dir2.display()
            );
        }
    }
}

pub struct FullBuildConfig {
    pub installation_data: InstallationData,
    pub cpp_build_config: CppBuildConfig,
    pub cpp_build_paths: CppBuildPaths,
}

pub fn get_full_build_config(crate_name: &str) -> Result<FullBuildConfig> {
    let installation_data = get_installation_data(crate_name)?;
    let mut cpp_build_paths = CppBuildPaths::new();
    let mut cpp_build_config_data = CppBuildConfigData::new();
    {
        let mut apply_installation_data = |name: &str, data: &InstallationData| {
            cpp_build_paths.add_include_path(&data.root_include_path);
            cpp_build_paths.add_include_path(&data.lib_include_path);
            if data.is_framework {
                cpp_build_paths.add_framework_path(&data.lib_path);
                cpp_build_config_data.add_linked_framework(framework_name(name));
            } else {
                cpp_build_paths.add_lib_path(&data.lib_path);
                cpp_build_config_data.add_linked_lib(real_lib_name(name));
            }
        };

        apply_installation_data(crate_name, &installation_data);
        for dep in lib_dependencies(crate_name)? {
            let dep_data = get_installation_data(dep)?;
            apply_installation_data(dep, &dep_data);
        }
    }
    let mut cpp_build_config = CppBuildConfig::new();
    cpp_build_config.add(target::Condition::True, cpp_build_config_data);
    {
        let mut data = CppBuildConfigData::new();
        data.add_compiler_flag("-std=gnu++11");
        cpp_build_config.add(target::Condition::Env(target::Env::Msvc).negate(), data);
    }
    {
        let mut data = CppBuildConfigData::new();
        data.add_compiler_flag("-fPIC");
        // msvc and mingw don't need this
        cpp_build_config.add(target::Condition::OS(target::OS::Windows).negate(), data);
    }
    {
        let mut data = CppBuildConfigData::new();
        data.set_library_type(CppLibraryType::Shared);
        cpp_build_config.add(target::Condition::Env(target::Env::Msvc), data);
    }
    Ok(FullBuildConfig {
        installation_data,
        cpp_build_config,
        cpp_build_paths,
    })
}

/// Returns library name of the specified module as
/// should be passed to the linker, e.g. `"Qt5Core"`.
pub fn real_lib_name(crate_name: &str) -> String {
    let sublib_name = crate_name.replace("qt_", "");
    let sublib_name_capitalized = sublib_name.to_class_case();
    format!("Qt5{}", sublib_name_capitalized)
}

/// Returns name of the module's include directory, e.g. `"QtCore"`.
pub fn lib_folder_name(crate_name: &str) -> String {
    let sublib_name = crate_name.replace("qt_", "");
    let sublib_name_capitalized = sublib_name.to_class_case();
    format!("Qt{}", sublib_name_capitalized)
}

/// Returns MacOS framework name of the specified module as
/// should be passed to the linker, e.g. `"QtCore"`.
pub fn framework_name(crate_name: &str) -> String {
    let sublib_name = crate_name.replace("qt_", "");
    let sublib_name_capitalized = sublib_name.to_class_case();
    format!("Qt{}", sublib_name_capitalized)
}

pub fn all_crate_names() -> &'static [&'static str] {
    &[
        "qt_core",
        "qt_gui",
        "qt_widgets",
        "qt_ui_tools",
        "qt_3d_core",
        "qt_3d_render",
        "qt_3d_input",
        "qt_3d_logic",
        "qt_3d_extras",
    ]
}

/// Returns list of modules this module depends on.
pub fn lib_dependencies(crate_name: &str) -> Result<&'static [&'static str]> {
    Ok(match crate_name {
        "qt_core" => &[],
        "qt_gui" => &["qt_core"],
        "qt_widgets" => &["qt_core", "qt_gui"],
        "qt_3d_core" => &["qt_core", "qt_gui"],
        "qt_3d_render" => &["qt_core", "qt_gui", "qt_3d_core"],
        "qt_3d_input" => &["qt_core", "qt_gui", "qt_3d_core"],
        "qt_3d_logic" => &["qt_core", "qt_gui", "qt_3d_core"],
        "qt_3d_extras" => &[
            "qt_core",
            "qt_gui",
            "qt_3d_core",
            "qt_3d_render",
            "qt_3d_input",
            "qt_3d_logic",
        ],
        "qt_ui_tools" => &["qt_core", "qt_gui", "qt_widgets"],
        "moqt_core" => &[],
        "moqt_gui" => &["moqt_core"],
        _ => bail!("Unknown crate name: {}", crate_name),
    })
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Example of using another function<commit_after>fn main() {
    println!("Hello, world!");

    another();
}

fn another() {
    println!("Hello from another function!");
}<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{WebGLCommand, WebGLError};
use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLShaderId};
use canvas_traits::webgl::{WebGLVersion, webgl_channel};
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::WebGLShaderBinding;
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::bindings::str::DOMString;
use dom::webgl_extensions::WebGLExtensions;
use dom::webgl_extensions::ext::extshadertexturelod::EXTShaderTextureLod;
use dom::webgl_extensions::ext::oesstandardderivatives::OESStandardDerivatives;
use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom_struct::dom_struct;
use mozangle::shaders::{BuiltInResources, Output, ShaderValidator};
use offscreen_gl_context::GLLimits;
use std::cell::Cell;
use std::os::raw::c_int;
use std::sync::{ONCE_INIT, Once};

#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum ShaderCompilationStatus {
    NotCompiled,
    Succeeded,
    Failed,
}

#[dom_struct]
pub struct WebGLShader {
    webgl_object: WebGLObject,
    id: WebGLShaderId,
    gl_type: u32,
    source: DomRefCell<DOMString>,
    info_log: DomRefCell<DOMString>,
    is_deleted: Cell<bool>,
    attached_counter: Cell<u32>,
    compilation_status: Cell<ShaderCompilationStatus>,
}

static GLSLANG_INITIALIZATION: Once = ONCE_INIT;

impl WebGLShader {
    fn new_inherited(
        context: &WebGLRenderingContext,
        id: WebGLShaderId,
        shader_type: u32,
    ) -> Self {
        GLSLANG_INITIALIZATION.call_once(|| ::mozangle::shaders::initialize().unwrap());
        Self {
            webgl_object: WebGLObject::new_inherited(context),
            id: id,
            gl_type: shader_type,
            source: Default::default(),
            info_log: Default::default(),
            is_deleted: Cell::new(false),
            attached_counter: Cell::new(0),
            compilation_status: Cell::new(ShaderCompilationStatus::NotCompiled),
        }
    }

    pub fn maybe_new(context: &WebGLRenderingContext, shader_type: u32) -> Option<DomRoot<Self>> {
        let (sender, receiver) = webgl_channel().unwrap();
        context.send_command(WebGLCommand::CreateShader(shader_type, sender));
        receiver.recv().unwrap().map(|id| WebGLShader::new(context, id, shader_type))
    }

    pub fn new(
        context: &WebGLRenderingContext,
        id: WebGLShaderId,
        shader_type: u32,
    ) -> DomRoot<Self> {
        reflect_dom_object(
            Box::new(WebGLShader::new_inherited(context, id, shader_type)),
            &*context.global(),
            WebGLShaderBinding::Wrap,
        )
    }
}

impl WebGLShader {
    pub fn id(&self) -> WebGLShaderId {
        self.id
    }

    pub fn gl_type(&self) -> u32 {
        self.gl_type
    }

    /// glCompileShader
    pub fn compile(
        &self,
        webgl_version: WebGLVersion,
        glsl_version: WebGLSLVersion,
        limits: &GLLimits,
        ext: &WebGLExtensions,
    ) -> WebGLResult<()> {
        if self.is_deleted.get() && !self.is_attached() {
            return Err(WebGLError::InvalidValue);
        }
        if self.compilation_status.get() != ShaderCompilationStatus::NotCompiled {
            debug!("Compiling already compiled shader {}", self.id);
        }

        let source = self.source.borrow();

        let params = BuiltInResources {
            MaxVertexAttribs: limits.max_vertex_attribs as c_int,
            MaxVertexUniformVectors: limits.max_vertex_uniform_vectors as c_int,
            MaxVaryingVectors: limits.max_varying_vectors as c_int,
            MaxVertexTextureImageUnits: limits.max_vertex_texture_image_units as c_int,
            MaxCombinedTextureImageUnits: limits.max_combined_texture_image_units as c_int,
            MaxTextureImageUnits: limits.max_texture_image_units as c_int,
            MaxFragmentUniformVectors: limits.max_fragment_uniform_vectors as c_int,
            OES_standard_derivatives: ext.is_enabled::<OESStandardDerivatives>() as c_int,
            EXT_shader_texture_lod: ext.is_enabled::<EXTShaderTextureLod>() as c_int,
            FragmentPrecisionHigh: 1,
            ..BuiltInResources::default()
        };
        let validator = match webgl_version {
            WebGLVersion::WebGL1 => {
                let output_format = if cfg!(any(target_os = "android", target_os = "ios")) {
                    Output::Essl
                } else {
                    Output::Glsl
                };
                ShaderValidator::for_webgl(self.gl_type,
                                            output_format,
                                            &params).unwrap()
            },
            WebGLVersion::WebGL2 => {
                let output_format = if cfg!(any(target_os = "android", target_os = "ios")) {
                    Output::Essl
                } else {
                    match (glsl_version.major, glsl_version.minor) {
                        (1, 30) => Output::Glsl130,
                        (1, 40) => Output::Glsl140,
                        (1, 50) => Output::Glsl150Core,
                        (3, 30) => Output::Glsl330Core,
                        (4, 0) => Output::Glsl400Core,
                        (4, 10) => Output::Glsl410Core,
                        (4, 20) => Output::Glsl420Core,
                        (4, 30) => Output::Glsl430Core,
                        (4, 40) => Output::Glsl440Core,
                        (4, _) => Output::Glsl450Core,
                        _ => Output::Glsl140
                    }
                };
                ShaderValidator::for_webgl2(self.gl_type,
                                            output_format,
                                            &params).unwrap()
            },
        };

        match validator.compile_and_translate(&[&source]) {
            Ok(translated_source) => {
                debug!("Shader translated: {}", translated_source);
                // NOTE: At this point we should be pretty sure that the compilation in the paint thread
                // will succeed.
                // It could be interesting to retrieve the info log from the paint thread though
                self.upcast::<WebGLObject>()
                    .context()
                    .send_command(WebGLCommand::CompileShader(self.id, translated_source));
                self.compilation_status.set(ShaderCompilationStatus::Succeeded);
            },
            Err(error) => {
                self.compilation_status.set(ShaderCompilationStatus::Failed);
                debug!("Shader {} compilation failed: {}", self.id, error);
            },
        }

        *self.info_log.borrow_mut() = validator.info_log().into();

        // TODO(emilio): More data (like uniform data) should be collected
        // here to properly validate uniforms.
        //
        // This requires a more complex interface with ANGLE, using C++
        // bindings and being extremely cautious about destructing things.
        Ok(())
    }

    /// Mark this shader as deleted (if it wasn't previously)
    /// and delete it as if calling glDeleteShader.
    /// Currently does not check if shader is attached
    pub fn delete(&self) {
        if !self.is_deleted.get() {
            self.is_deleted.set(true);
            self.upcast::<WebGLObject>()
                .context()
                .send_command(WebGLCommand::DeleteShader(self.id));
        }
    }

    pub fn is_deleted(&self) -> bool {
        self.is_deleted.get()
    }

    pub fn is_attached(&self) -> bool {
        self.attached_counter.get() > 0
    }

    pub fn increment_attached_counter(&self) {
        self.attached_counter.set(self.attached_counter.get() + 1);
    }

    pub fn decrement_attached_counter(&self) {
        assert!(self.attached_counter.get() > 0);
        self.attached_counter.set(self.attached_counter.get() - 1);
    }

    /// glGetShaderInfoLog
    pub fn info_log(&self) -> DOMString {
        self.info_log.borrow().clone()
    }

    /// Get the shader source
    pub fn source(&self) -> DOMString {
        self.source.borrow().clone()
    }

    /// glShaderSource
    pub fn set_source(&self, source: DOMString) {
        *self.source.borrow_mut() = source;
    }

    pub fn successfully_compiled(&self) -> bool {
        self.compilation_status.get() == ShaderCompilationStatus::Succeeded
    }
}

impl Drop for WebGLShader {
    fn drop(&mut self) {
        assert_eq!(self.attached_counter.get(), 0);
        self.delete();
    }
}
<commit_msg>Remove an obsolete todo in gl.compileShader()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{WebGLCommand, WebGLError};
use canvas_traits::webgl::{WebGLResult, WebGLSLVersion, WebGLShaderId};
use canvas_traits::webgl::{WebGLVersion, webgl_channel};
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::WebGLShaderBinding;
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::bindings::str::DOMString;
use dom::webgl_extensions::WebGLExtensions;
use dom::webgl_extensions::ext::extshadertexturelod::EXTShaderTextureLod;
use dom::webgl_extensions::ext::oesstandardderivatives::OESStandardDerivatives;
use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom_struct::dom_struct;
use mozangle::shaders::{BuiltInResources, Output, ShaderValidator};
use offscreen_gl_context::GLLimits;
use std::cell::Cell;
use std::os::raw::c_int;
use std::sync::{ONCE_INIT, Once};

#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum ShaderCompilationStatus {
    NotCompiled,
    Succeeded,
    Failed,
}

#[dom_struct]
pub struct WebGLShader {
    webgl_object: WebGLObject,
    id: WebGLShaderId,
    gl_type: u32,
    source: DomRefCell<DOMString>,
    info_log: DomRefCell<DOMString>,
    is_deleted: Cell<bool>,
    attached_counter: Cell<u32>,
    compilation_status: Cell<ShaderCompilationStatus>,
}

static GLSLANG_INITIALIZATION: Once = ONCE_INIT;

impl WebGLShader {
    fn new_inherited(
        context: &WebGLRenderingContext,
        id: WebGLShaderId,
        shader_type: u32,
    ) -> Self {
        GLSLANG_INITIALIZATION.call_once(|| ::mozangle::shaders::initialize().unwrap());
        Self {
            webgl_object: WebGLObject::new_inherited(context),
            id: id,
            gl_type: shader_type,
            source: Default::default(),
            info_log: Default::default(),
            is_deleted: Cell::new(false),
            attached_counter: Cell::new(0),
            compilation_status: Cell::new(ShaderCompilationStatus::NotCompiled),
        }
    }

    pub fn maybe_new(context: &WebGLRenderingContext, shader_type: u32) -> Option<DomRoot<Self>> {
        let (sender, receiver) = webgl_channel().unwrap();
        context.send_command(WebGLCommand::CreateShader(shader_type, sender));
        receiver.recv().unwrap().map(|id| WebGLShader::new(context, id, shader_type))
    }

    pub fn new(
        context: &WebGLRenderingContext,
        id: WebGLShaderId,
        shader_type: u32,
    ) -> DomRoot<Self> {
        reflect_dom_object(
            Box::new(WebGLShader::new_inherited(context, id, shader_type)),
            &*context.global(),
            WebGLShaderBinding::Wrap,
        )
    }
}

impl WebGLShader {
    pub fn id(&self) -> WebGLShaderId {
        self.id
    }

    pub fn gl_type(&self) -> u32 {
        self.gl_type
    }

    /// glCompileShader
    pub fn compile(
        &self,
        webgl_version: WebGLVersion,
        glsl_version: WebGLSLVersion,
        limits: &GLLimits,
        ext: &WebGLExtensions,
    ) -> WebGLResult<()> {
        if self.is_deleted.get() && !self.is_attached() {
            return Err(WebGLError::InvalidValue);
        }
        if self.compilation_status.get() != ShaderCompilationStatus::NotCompiled {
            debug!("Compiling already compiled shader {}", self.id);
        }

        let source = self.source.borrow();

        let params = BuiltInResources {
            MaxVertexAttribs: limits.max_vertex_attribs as c_int,
            MaxVertexUniformVectors: limits.max_vertex_uniform_vectors as c_int,
            MaxVaryingVectors: limits.max_varying_vectors as c_int,
            MaxVertexTextureImageUnits: limits.max_vertex_texture_image_units as c_int,
            MaxCombinedTextureImageUnits: limits.max_combined_texture_image_units as c_int,
            MaxTextureImageUnits: limits.max_texture_image_units as c_int,
            MaxFragmentUniformVectors: limits.max_fragment_uniform_vectors as c_int,
            OES_standard_derivatives: ext.is_enabled::<OESStandardDerivatives>() as c_int,
            EXT_shader_texture_lod: ext.is_enabled::<EXTShaderTextureLod>() as c_int,
            FragmentPrecisionHigh: 1,
            ..BuiltInResources::default()
        };
        let validator = match webgl_version {
            WebGLVersion::WebGL1 => {
                let output_format = if cfg!(any(target_os = "android", target_os = "ios")) {
                    Output::Essl
                } else {
                    Output::Glsl
                };
                ShaderValidator::for_webgl(self.gl_type,
                                            output_format,
                                            &params).unwrap()
            },
            WebGLVersion::WebGL2 => {
                let output_format = if cfg!(any(target_os = "android", target_os = "ios")) {
                    Output::Essl
                } else {
                    match (glsl_version.major, glsl_version.minor) {
                        (1, 30) => Output::Glsl130,
                        (1, 40) => Output::Glsl140,
                        (1, 50) => Output::Glsl150Core,
                        (3, 30) => Output::Glsl330Core,
                        (4, 0) => Output::Glsl400Core,
                        (4, 10) => Output::Glsl410Core,
                        (4, 20) => Output::Glsl420Core,
                        (4, 30) => Output::Glsl430Core,
                        (4, 40) => Output::Glsl440Core,
                        (4, _) => Output::Glsl450Core,
                        _ => Output::Glsl140
                    }
                };
                ShaderValidator::for_webgl2(self.gl_type,
                                            output_format,
                                            &params).unwrap()
            },
        };

        match validator.compile_and_translate(&[&source]) {
            Ok(translated_source) => {
                debug!("Shader translated: {}", translated_source);
                // NOTE: At this point we should be pretty sure that the compilation in the paint thread
                // will succeed.
                // It could be interesting to retrieve the info log from the paint thread though
                self.upcast::<WebGLObject>()
                    .context()
                    .send_command(WebGLCommand::CompileShader(self.id, translated_source));
                self.compilation_status.set(ShaderCompilationStatus::Succeeded);
            },
            Err(error) => {
                self.compilation_status.set(ShaderCompilationStatus::Failed);
                debug!("Shader {} compilation failed: {}", self.id, error);
            },
        }

        *self.info_log.borrow_mut() = validator.info_log().into();

        Ok(())
    }

    /// Mark this shader as deleted (if it wasn't previously)
    /// and delete it as if calling glDeleteShader.
    /// Currently does not check if shader is attached
    pub fn delete(&self) {
        if !self.is_deleted.get() {
            self.is_deleted.set(true);
            self.upcast::<WebGLObject>()
                .context()
                .send_command(WebGLCommand::DeleteShader(self.id));
        }
    }

    pub fn is_deleted(&self) -> bool {
        self.is_deleted.get()
    }

    pub fn is_attached(&self) -> bool {
        self.attached_counter.get() > 0
    }

    pub fn increment_attached_counter(&self) {
        self.attached_counter.set(self.attached_counter.get() + 1);
    }

    pub fn decrement_attached_counter(&self) {
        assert!(self.attached_counter.get() > 0);
        self.attached_counter.set(self.attached_counter.get() - 1);
    }

    /// glGetShaderInfoLog
    pub fn info_log(&self) -> DOMString {
        self.info_log.borrow().clone()
    }

    /// Get the shader source
    pub fn source(&self) -> DOMString {
        self.source.borrow().clone()
    }

    /// glShaderSource
    pub fn set_source(&self, source: DOMString) {
        *self.source.borrow_mut() = source;
    }

    pub fn successfully_compiled(&self) -> bool {
        self.compilation_status.get() == ShaderCompilationStatus::Succeeded
    }
}

impl Drop for WebGLShader {
    fn drop(&mut self) {
        assert_eq!(self.attached_counter.get(), 0);
        self.delete();
    }
}
<|endoftext|>


<commit_before><commit_msg>Make sure regen script succeeded before building.<commit_after><|endoftext|>


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

//! Grin server implementation, glues the different parts of the system (mostly
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
//! as a facade.

use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::thread;
use std::time;

use futures::{Future, Stream};
use tokio_core::reactor;
use tokio_timer::Timer;

use adapters::*;
use api;
use chain;
use miner;
use p2p;
use pool;
use seed;
use sync;
use types::*;
use pow;
use util::LOGGER;

use core::global;

/// Grin server holding internal structures.
pub struct Server {
	/// server config
	pub config: ServerConfig,
	/// event handle
	evt_handle: reactor::Handle,
	/// handle to our network server
	p2p: Arc<p2p::Server>,
	/// data store access
	chain: Arc<chain::Chain>,
	/// in-memory transaction pool
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	net_adapter: Arc<NetToChainAdapter>,
}

impl Server {
	/// Instantiates and starts a new server.
	pub fn start(config: ServerConfig) -> Result<Server, Error> {
		let mut evtlp = reactor::Core::new().unwrap();

		let mut mining_config = config.mining_config.clone();
		let serv = Server::future(config, &evtlp.handle())?;
		if mining_config.as_mut().unwrap().enable_mining {
			serv.start_miner(mining_config.unwrap());
		}

		let forever = Timer::default()
			.interval(time::Duration::from_secs(60))
			.for_each(move |_| {
				debug!(LOGGER, "event loop running");
				Ok(())
			})
			.map_err(|_| ());

		evtlp.run(forever).unwrap();
		Ok(serv)
	}

	/// Instantiates a new server associated with the provided future reactor.
	pub fn future(mut config: ServerConfig, evt_handle: &reactor::Handle) -> Result<Server, Error> {

		let pool_adapter = Arc::new(PoolToChainAdapter::new());
		let tx_pool = Arc::new(RwLock::new(pool::TransactionPool::new(
			config.pool_config.clone(),
			pool_adapter.clone(),
		)));

		let chain_adapter = Arc::new(ChainToPoolAndNetAdapter::new(tx_pool.clone()));

		let mut genesis_block = None;
		if !chain::Chain::chain_exists(config.db_root.clone()) {
			genesis_block = pow::mine_genesis_block(config.mining_config.clone());
		}

		let shared_chain = Arc::new(chain::Chain::init(
			config.db_root.clone(),
			chain_adapter.clone(),
			genesis_block,
			pow::verify_size,
		)?);

		pool_adapter.set_chain(shared_chain.clone());

		let peer_store = Arc::new(p2p::PeerStore::new(config.db_root.clone())?);
		let net_adapter = Arc::new(NetToChainAdapter::new(
			shared_chain.clone(),
			tx_pool.clone(),
			peer_store.clone(),
		));
		let p2p_server = Arc::new(p2p::Server::new(
			config.capabilities,
			config.p2p_config.unwrap(),
			net_adapter.clone(),
		));
		chain_adapter.init(p2p_server.clone());

		let seed = seed::Seeder::new(config.capabilities, peer_store.clone(), p2p_server.clone());
		match config.seeding_type.clone() {
			Seeding::None => {
				warn!(
					LOGGER,
					"No seed configured, will stay solo until connected to"
				);
			}
			Seeding::List => {
				seed.connect_and_monitor(
					evt_handle.clone(),
					seed::predefined_seeds(config.seeds.as_mut().unwrap().clone()),
				);
			}
			Seeding::WebStatic => {
				seed.connect_and_monitor(evt_handle.clone(), seed::web_seeds(evt_handle.clone()));
			}
		}

		if config.seeding_type != Seeding::None {
			let sync = sync::Syncer::new(shared_chain.clone(), p2p_server.clone());
			net_adapter.start_sync(sync);
		}

		evt_handle.spawn(p2p_server.start(evt_handle.clone()).map_err(|_| ()));

		info!(LOGGER, "Starting rest apis at: {}", &config.api_http_addr);

		api::start_rest_apis(
			config.api_http_addr.clone(),
			shared_chain.clone(),
			tx_pool.clone(),
		);

		warn!(LOGGER, "Grin server started.");
		Ok(Server {
			config: config,
			evt_handle: evt_handle.clone(),
			p2p: p2p_server,
			chain: shared_chain,
			tx_pool: tx_pool,
			net_adapter: net_adapter,
		})
	}

	/// Asks the server to connect to a peer at the provided network address.
	pub fn connect_peer(&self, addr: SocketAddr) -> Result<(), Error> {
		let handle = self.evt_handle.clone();
		handle.spawn(
			self.p2p
				.connect_peer(addr, handle.clone())
				.map(|_| ())
				.map_err(|_| ()),
		);
		Ok(())
	}

	/// Number of peers
	pub fn peer_count(&self) -> u32 {
		self.p2p.peer_count()
	}

	/// Start mining for blocks on a separate thread. Uses toy miner by default,
	/// mostly for testing, but can also load a plugin from cuckoo-miner
	pub fn start_miner(&self, config: pow::types::MinerConfig) {
		let cuckoo_size = global::sizeshift();
		let proof_size = global::proofsize();
		let net_adapter = self.net_adapter.clone();

		let mut miner = miner::Miner::new(config.clone(), self.chain.clone(), self.tx_pool.clone());
		miner.set_debug_output_id(format!("Port {}", self.config.p2p_config.unwrap().port));
		thread::spawn(move || {
			let secs_5 = time::Duration::from_secs(5);
			while net_adapter.syncing() {
				thread::sleep(secs_5);
			}
			miner.run_loop(config.clone(), cuckoo_size as u32, proof_size);
		});
	}

	/// The chain head
	pub fn head(&self) -> chain::Tip {
		self.chain.head().unwrap()
	}

	/// Returns a set of stats about this server. This and the ServerStats
	/// structure
	/// can be updated over time to include any information needed by tests or
	/// other
	/// consumers

	pub fn get_server_stats(&self) -> Result<ServerStats, Error> {
		Ok(ServerStats {
			peer_count: self.peer_count(),
			head: self.head(),
		})
	}
}
<commit_msg>Ditto<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Grin server implementation, glues the different parts of the system (mostly
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
//! as a facade.

use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::thread;
use std::time;

use futures::{Future, Stream};
use tokio_core::reactor;
use tokio_timer::Timer;

use adapters::*;
use api;
use chain;
use miner;
use p2p;
use pool;
use seed;
use sync;
use types::*;
use pow;
use util::LOGGER;

use core::global;

/// Grin server holding internal structures.
pub struct Server {
	/// server config
	pub config: ServerConfig,
	/// event handle
	evt_handle: reactor::Handle,
	/// handle to our network server
	p2p: Arc<p2p::Server>,
	/// data store access
	chain: Arc<chain::Chain>,
	/// in-memory transaction pool
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	net_adapter: Arc<NetToChainAdapter>,
}

impl Server {
	/// Instantiates and starts a new server.
	pub fn start(config: ServerConfig) -> Result<Server, Error> {
		let mut evtlp = reactor::Core::new().unwrap();

		let mut mining_config = config.mining_config.clone();
		let serv = Server::future(config, &evtlp.handle())?;
		if mining_config.as_mut().unwrap().enable_mining {
			serv.start_miner(mining_config.unwrap());
		}

		let forever = Timer::default()
			.interval(time::Duration::from_secs(60))
			.for_each(move |_| {
				debug!(LOGGER, "event loop running");
				Ok(())
			})
			.map_err(|_| ());

		evtlp.run(forever).unwrap();
		Ok(serv)
	}

	/// Instantiates a new server associated with the provided future reactor.
	pub fn future(mut config: ServerConfig, evt_handle: &reactor::Handle) -> Result<Server, Error> {

		let pool_adapter = Arc::new(PoolToChainAdapter::new());
		let tx_pool = Arc::new(RwLock::new(pool::TransactionPool::new(
			config.pool_config.clone(),
			pool_adapter.clone(),
		)));

		let chain_adapter = Arc::new(ChainToPoolAndNetAdapter::new(tx_pool.clone()));

		let mut genesis_block = None;
		if !chain::Chain::chain_exists(config.db_root.clone()) {
			genesis_block = pow::mine_genesis_block(config.mining_config.clone());
		}

		let shared_chain = Arc::new(chain::Chain::init(
			config.db_root.clone(),
			chain_adapter.clone(),
			genesis_block,
			pow::verify_size,
		)?);

		pool_adapter.set_chain(shared_chain.clone());

		let peer_store = Arc::new(p2p::PeerStore::new(config.db_root.clone())?);
		let net_adapter = Arc::new(NetToChainAdapter::new(
			shared_chain.clone(),
			tx_pool.clone(),
			peer_store.clone(),
		));
		let p2p_server = Arc::new(p2p::Server::new(
			config.capabilities,
			config.p2p_config.unwrap(),
			net_adapter.clone(),
		));
		chain_adapter.init(p2p_server.clone());

		let seed = seed::Seeder::new(config.capabilities, peer_store.clone(), p2p_server.clone());
		match config.seeding_type.clone() {
			Seeding::None => {
				warn!(
					LOGGER,
					"No seed configured, will stay solo until connected to"
				);
			}
			Seeding::List => {
				seed.connect_and_monitor(
					evt_handle.clone(),
					seed::predefined_seeds(config.seeds.as_mut().unwrap().clone()),
				);
			}
			Seeding::WebStatic => {
				seed.connect_and_monitor(evt_handle.clone(), seed::web_seeds(evt_handle.clone()));
			}
			_ => {},
		}

		if config.seeding_type != Seeding::None {
			let sync = sync::Syncer::new(shared_chain.clone(), p2p_server.clone());
			net_adapter.start_sync(sync);
		}

		evt_handle.spawn(p2p_server.start(evt_handle.clone()).map_err(|_| ()));

		info!(LOGGER, "Starting rest apis at: {}", &config.api_http_addr);

		api::start_rest_apis(
			config.api_http_addr.clone(),
			shared_chain.clone(),
			tx_pool.clone(),
		);

		warn!(LOGGER, "Grin server started.");
		Ok(Server {
			config: config,
			evt_handle: evt_handle.clone(),
			p2p: p2p_server,
			chain: shared_chain,
			tx_pool: tx_pool,
			net_adapter: net_adapter,
		})
	}

	/// Asks the server to connect to a peer at the provided network address.
	pub fn connect_peer(&self, addr: SocketAddr) -> Result<(), Error> {
		let handle = self.evt_handle.clone();
		handle.spawn(
			self.p2p
				.connect_peer(addr, handle.clone())
				.map(|_| ())
				.map_err(|_| ()),
		);
		Ok(())
	}

	/// Number of peers
	pub fn peer_count(&self) -> u32 {
		self.p2p.peer_count()
	}

	/// Start mining for blocks on a separate thread. Uses toy miner by default,
	/// mostly for testing, but can also load a plugin from cuckoo-miner
	pub fn start_miner(&self, config: pow::types::MinerConfig) {
		let cuckoo_size = global::sizeshift();
		let proof_size = global::proofsize();
		let net_adapter = self.net_adapter.clone();

		let mut miner = miner::Miner::new(config.clone(), self.chain.clone(), self.tx_pool.clone());
		miner.set_debug_output_id(format!("Port {}", self.config.p2p_config.unwrap().port));
		thread::spawn(move || {
			let secs_5 = time::Duration::from_secs(5);
			while net_adapter.syncing() {
				thread::sleep(secs_5);
			}
			miner.run_loop(config.clone(), cuckoo_size as u32, proof_size);
		});
	}

	/// The chain head
	pub fn head(&self) -> chain::Tip {
		self.chain.head().unwrap()
	}

	/// Returns a set of stats about this server. This and the ServerStats
	/// structure
	/// can be updated over time to include any information needed by tests or
	/// other
	/// consumers

	pub fn get_server_stats(&self) -> Result<ServerStats, Error> {
		Ok(ServerStats {
			peer_count: self.peer_count(),
			head: self.head(),
		})
	}
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;
use std::fmt;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use parser::ast::*;
use evaluator::environment::*;

#[derive(PartialEq, Debug, Clone)]
pub enum Object {
    Integer(i64),
    Boolean(bool),
    String(String),
    Array(Vec<Object>),
    Hash(HashMap<Object, Object>),
    Function(Vec<Ident>, BlockStmt, Rc<RefCell<Environment>>),
    Builtin(String, usize, BuiltinFunction),
    Null,
    ReturnValue(Box<Object>),
    Error(String),
}

impl Object {
    pub fn is_returned(&self) -> bool {
        match self {
            &Object::ReturnValue(_) => true,
            _ => false,
        }
    }

    pub fn returned(&self) -> Self {
        match self {
            &Object::ReturnValue(box ref o) => o.clone(),
            &ref o => o.clone(),
        }
    }
}

pub type BuiltinFunction = fn(Vec<Object>) -> Result<Object, String>;

impl fmt::Display for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Object::Integer(ref i) => write!(f, "{}", i),
            &Object::Boolean(ref b) => if *b { write!(f, "true") } else { write!(f, "false") },
            &Object::String(ref s) => write!(f, "{}", s),
            &Object::Array(ref v) => {
                let mut fmt_string = String::new();
                fmt_string.push_str("[");
                for o in v {
                    fmt_string.push_str(format!("{}, ", o).as_str());
                }
                fmt_string.push_str("]");
                write!(f, "{}", fmt_string)
            },
            &Object::Hash(ref hashmap) => {
                let mut fmt_string = String::new();
                fmt_string.push_str("{");
                for (k, v) in hashmap {
                    fmt_string.push_str(format!("{} : {}, ", k, v).as_str());
                }
                fmt_string.push_str("}");
                write!(f, "{}", fmt_string)
            },
            &Object::Function(_, _, _) => write!(f, "[function]"),
            &Object::Builtin(ref name, _, _) => write!(f, "[built-in function: {}]", *name),
            &Object::Null => write!(f, "null"),
            &Object::ReturnValue(box ref o) => write!(f, "{}", *o),
            &Object::Error(ref s) => write!(f, "Error: {}", s),
        }
    }
}

impl Eq for Object { }

impl Hash for Object {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            &Object::Integer(ref i) => i.hash(state),
            &Object::Boolean(ref b) => b.hash(state),
            &Object::String(ref s) => s.hash(state),
            _ => "".hash(state),
        }
    }
}
<commit_msg>output<commit_after>use std::cell::RefCell;
use std::rc::Rc;
use std::fmt;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use parser::ast::*;
use evaluator::environment::*;

#[derive(PartialEq, Debug, Clone)]
pub enum Object {
    Integer(i64),
    Boolean(bool),
    String(String),
    Array(Vec<Object>),
    Hash(HashMap<Object, Object>),
    Function(Vec<Ident>, BlockStmt, Rc<RefCell<Environment>>),
    Builtin(String, usize, BuiltinFunction),
    Null,
    ReturnValue(Box<Object>),
    Error(String),
}

impl Object {
    pub fn is_returned(&self) -> bool {
        match self {
            &Object::ReturnValue(_) => true,
            _ => false,
        }
    }

    pub fn returned(&self) -> Self {
        match self {
            &Object::ReturnValue(box ref o) => o.clone(),
            &ref o => o.clone(),
        }
    }
}

pub type BuiltinFunction = fn(Vec<Object>) -> Result<Object, String>;

impl fmt::Display for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Object::Integer(ref i) => write!(f, "{}", i),
            &Object::Boolean(ref b) => if *b { write!(f, "true") } else { write!(f, "false") },
            &Object::String(ref s) => write!(f, "{}", s),
            &Object::Array(ref v) => {
                let mut fmt_string = String::new();
                let mut i = 0;
                fmt_string.push_str("[");
                for o in v {
                    fmt_string.push_str(format!("{}", o).as_str());
                    if i < v.len() - 1 {
                        fmt_string.push_str(format!(", ").as_str());
                    }
                    i = i + 1;
                }
                fmt_string.push_str("]");
                write!(f, "{:?}", fmt_string)
            },
            &Object::Hash(ref hashmap) => {
                let mut fmt_string = String::new();
                let mut i = 0;
                fmt_string.push_str("{");
                for (k, v) in hashmap {
                    fmt_string.push_str(format!("{} : {}", k, v).as_str());
                    if i < hashmap.len() - 1 {
                        fmt_string.push_str(format!(", ").as_str());
                    }
                    i = i + 1;
                }
                fmt_string.push_str("}");
                write!(f, "{}", fmt_string)
            },
            &Object::Function(_, _, _) => write!(f, "[function]"),
            &Object::Builtin(ref name, _, _) => write!(f, "[built-in function: {}]", *name),
            &Object::Null => write!(f, "null"),
            &Object::ReturnValue(box ref o) => write!(f, "{}", *o),
            &Object::Error(ref s) => write!(f, "Error: {}", s),
        }
    }
}

impl Eq for Object { }

impl Hash for Object {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            &Object::Integer(ref i) => i.hash(state),
            &Object::Boolean(ref b) => b.hash(state),
            &Object::String(ref s) => s.hash(state),
            _ => "".hash(state),
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library 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; version
// 2.1 of the License.
//
// This library 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 this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::Path;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;

use libimagstore::store::Store;
use libimagentryref::reference::Ref;
use libimagentryref::flags::RefFlags;

use email::MimeMessage;
use email::results::ParsingResult as EmailParsingResult;

use hasher::MailHasher;
use result::Result;
use error::{MapErrInto, MailErrorKind as MEK};

struct Buffer(String);

impl Buffer {
    pub fn parsed(&self) -> EmailParsingResult<MimeMessage> {
        MimeMessage::parse(&self.0)
    }
}

impl From<String> for Buffer {
    fn from(data: String) -> Buffer {
        Buffer(data)
    }
}

pub struct Mail<'a>(Ref<'a>, Buffer);

impl<'a> Mail<'a> {

    /// Imports a mail from the Path passed
    pub fn import_from_path<P: AsRef<Path>>(store: &Store, p: P) -> Result<Mail> {
        let h = MailHasher::new();
        let f = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);
        let p = PathBuf::from(p.as_ref());

        Ref::create_with_hasher(store, p, f, h)
            .map_err_into(MEK::RefCreationError)
            .and_then(|reference| {
                reference.fs_file()
                    .map_err_into(MEK::RefHandlingError)
                    .and_then(|path| File::open(path).map_err_into(MEK::IOError))
                    .and_then(|mut file| {
                        let mut s = String::new();
                        file.read_to_string(&mut s)
                            .map(|_| s)
                            .map_err_into(MEK::IOError)
                    })
                    .map(Buffer::from)
                    .map(|buffer| Mail(reference, buffer))
            })
    }

    /// Opens a mail by the passed hash
    pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
        Ref::get_by_hash(store, String::from(hash.as_ref()))
            .map_err_into(MEK::FetchByHashError)
            .map_err_into(MEK::FetchError)
            .and_then(|o| match o {
                Some(r) => Mail::from_ref(r).map(Some),
                None => Ok(None),
            })

    }

    /// Implement me as TryFrom as soon as it is stable
    pub fn from_ref(r: Ref<'a>) -> Result<Mail> {
        r.fs_file()
            .map_err_into(MEK::RefHandlingError)
            .and_then(|path| File::open(path).map_err_into(MEK::IOError))
            .and_then(|mut file| {
                let mut s = String::new();
                file.read_to_string(&mut s)
                    .map(|_| s)
                    .map_err_into(MEK::IOError)
            })
            .map(Buffer::from)
            .map(|buffer| Mail(r, buffer))
    }

    pub fn get_field(&self, field: &str) -> Result<Option<String>> {
        self.1
            .parsed()
            .map_err_into(MEK::MailParsingError)
            .map(|parsed| {
                parsed.headers
                    .iter()
                    .filter(|hdr| hdr.name == field)
                    .nth(0)
                    .and_then(|field| field.get_value().ok())
            })
    }

    pub fn get_from(&self) -> Result<Option<String>> {
        self.get_field("From")
    }

    pub fn get_to(&self) -> Result<Option<String>> {
        self.get_field("To")
    }

    pub fn get_subject(&self) -> Result<Option<String>> {
        self.get_field("Subject")
    }

    pub fn get_message_id(&self) -> Result<Option<String>> {
        self.get_field("Message-ID")
    }

    pub fn get_in_reply_to(&self) -> Result<Option<String>> {
        self.get_field("In-Reply-To")
    }

}
<commit_msg>Add debug messages<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library 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; version
// 2.1 of the License.
//
// This library 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 this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::Path;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;

use libimagstore::store::Store;
use libimagentryref::reference::Ref;
use libimagentryref::flags::RefFlags;

use email::MimeMessage;
use email::results::ParsingResult as EmailParsingResult;

use hasher::MailHasher;
use result::Result;
use error::{MapErrInto, MailErrorKind as MEK};

struct Buffer(String);

impl Buffer {
    pub fn parsed(&self) -> EmailParsingResult<MimeMessage> {
        MimeMessage::parse(&self.0)
    }
}

impl From<String> for Buffer {
    fn from(data: String) -> Buffer {
        Buffer(data)
    }
}

pub struct Mail<'a>(Ref<'a>, Buffer);

impl<'a> Mail<'a> {

    /// Imports a mail from the Path passed
    pub fn import_from_path<P: AsRef<Path>>(store: &Store, p: P) -> Result<Mail> {
        debug!("Importing Mail from path");
        let h = MailHasher::new();
        let f = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);
        let p = PathBuf::from(p.as_ref());

        Ref::create_with_hasher(store, p, f, h)
            .map_err_into(MEK::RefCreationError)
            .and_then(|reference| {
                debug!("Build reference file: {:?}", reference);
                reference.fs_file()
                    .map_err_into(MEK::RefHandlingError)
                    .and_then(|path| File::open(path).map_err_into(MEK::IOError))
                    .and_then(|mut file| {
                        let mut s = String::new();
                        file.read_to_string(&mut s)
                            .map(|_| s)
                            .map_err_into(MEK::IOError)
                    })
                    .map(Buffer::from)
                    .map(|buffer| Mail(reference, buffer))
            })
    }

    /// Opens a mail by the passed hash
    pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
        debug!("Opening Mail by Hash");
        Ref::get_by_hash(store, String::from(hash.as_ref()))
            .map_err_into(MEK::FetchByHashError)
            .map_err_into(MEK::FetchError)
            .and_then(|o| match o {
                Some(r) => Mail::from_ref(r).map(Some),
                None => Ok(None),
            })

    }

    /// Implement me as TryFrom as soon as it is stable
    pub fn from_ref(r: Ref<'a>) -> Result<Mail> {
        debug!("Building Mail object from Ref: {:?}", r);
        r.fs_file()
            .map_err_into(MEK::RefHandlingError)
            .and_then(|path| File::open(path).map_err_into(MEK::IOError))
            .and_then(|mut file| {
                let mut s = String::new();
                file.read_to_string(&mut s)
                    .map(|_| s)
                    .map_err_into(MEK::IOError)
            })
            .map(Buffer::from)
            .map(|buffer| Mail(r, buffer))
    }

    pub fn get_field(&self, field: &str) -> Result<Option<String>> {
        debug!("Getting field in mail: {:?}", field);
        self.1
            .parsed()
            .map_err_into(MEK::MailParsingError)
            .map(|parsed| {
                parsed.headers
                    .iter()
                    .filter(|hdr| hdr.name == field)
                    .nth(0)
                    .and_then(|field| field.get_value().ok())
            })
    }

    pub fn get_from(&self) -> Result<Option<String>> {
        self.get_field("From")
    }

    pub fn get_to(&self) -> Result<Option<String>> {
        self.get_field("To")
    }

    pub fn get_subject(&self) -> Result<Option<String>> {
        self.get_field("Subject")
    }

    pub fn get_message_id(&self) -> Result<Option<String>> {
        self.get_field("Message-ID")
    }

    pub fn get_in_reply_to(&self) -> Result<Option<String>> {
        self.get_field("In-Reply-To")
    }

}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

fn get_input() -> std::io::Result<String> {
    let mut file = File::open("07.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents)
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Value<'a> {
    Wire(&'a str),
    Num(u16)
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Action<'a> {
    Assign(Value<'a>),
    And(Value<'a>, Value<'a>),
    Or(Value<'a>, Value<'a>),
    LShift(Value<'a>, u16),
    RShift(Value<'a>, u16),
    Not(Value<'a>)
}

#[derive(Debug)]
struct Instruction<'a> {
    wire: &'a str,
    action: Action<'a>
}

fn parse_value(string: &str) -> Value {
    match string.parse::<u16>() {
        Ok(x) => Value::Num(x),
        Err(_) => Value::Wire(string)
    }
}

fn parse_line(line: &str) -> Option<Instruction> {
    let tokens = line.split(" -> ").collect::<Vec<_>>();
    let left_tokens = tokens[0].split(' ').collect::<Vec<_>>();

    let wire = tokens[1];
    let action = match left_tokens.len() {
        l if l == 1 => {
            Action::Assign(parse_value(left_tokens[0]))
        },
        l if l == 2 => {
            Action::Not(parse_value(left_tokens[1]))
        },
        l if l == 3 => {
            let arg1 = left_tokens[0];
            let arg2 = left_tokens[2];

            match left_tokens[1] {
                "AND" => {
                    Action::And(parse_value(arg1), parse_value(arg2))
                },
                "OR" => {
                    Action::Or(parse_value(arg1), parse_value(arg2))
                },
                "LSHIFT" => {
                    Action::LShift(parse_value(arg1), arg2.parse::<u16>().unwrap())
                },
                "RSHIFT" => {
                    Action::RShift(parse_value(arg1), arg2.parse::<u16>().unwrap())
                },
                _ => return None
            }
        },
        _ => return None
    };

    Some(Instruction {wire, action})
}

fn resolve<'a>(
    instructions: &Vec<Instruction<'a>>,
    cache: &mut HashMap<&'a str, u16>,
    value: Value<'a>
) -> u16 {
    match value {
        Value::Num(x) => x,
        Value::Wire(wire) => {
            if let Some(x) = cache.get(wire) {
                return *x;
            }

            let instruction = instructions.iter()
                .find(|&i| i.wire == wire).unwrap();

            let num = match instruction.action {
                Action::Assign(x) => {
                    resolve(instructions, cache, x)
                },
                Action::And(x, y) => {
                    resolve(instructions, cache, x)
                    & resolve(instructions, cache, y)
                },
                Action::Or(x, y) => {
                    resolve(instructions, cache, x)
                    | resolve(instructions, cache, y)
                },
                Action::LShift(x, y) => {
                    resolve(instructions, cache, x) << y
                },
                Action::RShift(x, y) => {
                    resolve(instructions, cache, x) >> y
                },
                Action::Not(x) => {
                    !resolve(instructions, cache, x)
                }
            };

            cache.insert(wire, num);
            num
        }
    }
}

fn main() {
    let input = get_input().unwrap();

    let mut instructions = input.lines().filter_map(parse_line).collect::<Vec<_>>();
    let mut cache = HashMap::new();
    let result = resolve(&instructions, &mut cache, Value::Wire("a"));

    println!("Part 1: {}", result);

    let index = instructions.iter().position(|i| i.wire == "b").unwrap();

    instructions[index] = Instruction {
        wire: "b",
        action: Action::Assign(Value::Num(result))
    };

    let mut cache: HashMap<&str, u16> = HashMap::new();
    let result = resolve(&instructions, &mut cache, Value::Wire("a"));

    println!("Part 2: {}", result);
}
<commit_msg>Add Circuit struct<commit_after>use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

fn get_input() -> std::io::Result<String> {
    let mut file = File::open("07.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents)
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Value<'a> {
    Wire(&'a str),
    Num(u16)
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Action<'a> {
    Assign(Value<'a>),
    And(Value<'a>, Value<'a>),
    Or(Value<'a>, Value<'a>),
    LShift(Value<'a>, u16),
    RShift(Value<'a>, u16),
    Not(Value<'a>)
}

#[derive(Debug)]
struct Instruction<'a> {
    wire: &'a str,
    action: Action<'a>
}

struct Circuit<'a, 'b: 'a> {
    instructions: &'a Vec<Instruction<'b>>,
    cache: HashMap<&'b str, u16>
}

impl<'a, 'b> Circuit<'a, 'b> {
    fn new(instructions: &'a Vec<Instruction<'b>>) -> Circuit<'a, 'b> {
        let cache = HashMap::new();
        Circuit {instructions, cache}
    }

    fn resolve(&mut self, value: Value<'b>) -> u16 {
        match value {
            Value::Num(x) => x,
            Value::Wire(wire) => {
                if let Some(x) = self.cache.get(wire) {
                    return *x;
                }

                let instruction = self.instructions.iter()
                    .find(|&i| i.wire == wire).unwrap();

                let num = match instruction.action {
                    Action::Assign(x) => self.resolve(x),
                    Action::And(x, y) => self.resolve(x) & self.resolve(y),
                    Action::Or(x, y) => self.resolve(x) | self.resolve(y),
                    Action::LShift(x, y) => self.resolve(x) << y,
                    Action::RShift(x, y) => self.resolve(x) >> y,
                    Action::Not(x) => !self.resolve(x)
                };

                self.cache.insert(wire, num);
                num
            }
        }
    }
}

fn parse_value(string: &str) -> Value {
    match string.parse::<u16>() {
        Ok(x) => Value::Num(x),
        Err(_) => Value::Wire(string)
    }
}

fn parse_line(line: &str) -> Option<Instruction> {
    let tokens = line.split(" -> ").collect::<Vec<_>>();
    let left_tokens = tokens[0].split(' ').collect::<Vec<_>>();

    let wire = tokens[1];
    let action = match left_tokens.len() {
        l if l == 1 => {
            Action::Assign(parse_value(left_tokens[0]))
        },
        l if l == 2 => {
            Action::Not(parse_value(left_tokens[1]))
        },
        l if l == 3 => {
            let arg1 = left_tokens[0];
            let arg2 = left_tokens[2];

            match left_tokens[1] {
                "AND" => {
                    Action::And(parse_value(arg1), parse_value(arg2))
                },
                "OR" => {
                    Action::Or(parse_value(arg1), parse_value(arg2))
                },
                "LSHIFT" => {
                    Action::LShift(parse_value(arg1), arg2.parse::<u16>().unwrap())
                },
                "RSHIFT" => {
                    Action::RShift(parse_value(arg1), arg2.parse::<u16>().unwrap())
                },
                _ => return None
            }
        },
        _ => return None
    };

    Some(Instruction {wire, action})
}

fn main() {
    let input = get_input().unwrap();
    let mut instructions = input.lines().filter_map(parse_line).collect::<Vec<_>>();
    let mut result: u16;

    {
        let mut circuit = Circuit::new(&instructions);
        result = circuit.resolve(Value::Wire("a"));

        println!("Part 1: {}", result);
    }

    {
        let index = instructions.iter().position(|i| i.wire == "b").unwrap();

        instructions[index] = Instruction {
            wire: "b",
            action: Action::Assign(Value::Num(result))
        };

        let mut circuit = Circuit::new(&instructions);
        result = circuit.resolve(Value::Wire("a"));

        println!("Part 2: {}", result);
    }
}
<|endoftext|>


<commit_before>use unicode_normalization::char::is_combining_mark;

fn _to_ascii(domain: &str) -> Result<String, idna::Errors> {
    idna::Config::default()
        .verify_dns_length(true)
        .use_std3_ascii_rules(true)
        .to_ascii(domain)
}

#[test]
fn test_v5() {
    // IdnaTest:784 蔏｡𑰺
    assert!(is_combining_mark('\u{11C3A}'));
    assert!(_to_ascii("\u{11C3A}").is_err());
    assert!(_to_ascii("\u{850f}.\u{11C3A}").is_err());
    assert!(_to_ascii("\u{850f}\u{ff61}\u{11C3A}").is_err());
}

#[test]
fn test_v8_bidi_rules() {
    assert_eq!(_to_ascii("abc").unwrap(), "abc");
    assert_eq!(_to_ascii("123").unwrap(), "123");
    assert_eq!(_to_ascii("אבּג").unwrap(), "xn--kdb3bdf");
    assert_eq!(_to_ascii("ابج").unwrap(), "xn--mgbcm");
    assert_eq!(_to_ascii("abc.ابج").unwrap(), "abc.xn--mgbcm");
    assert_eq!(_to_ascii("אבּג.ابج").unwrap(), "xn--kdb3bdf.xn--mgbcm");

    // Bidi domain names cannot start with digits
    assert!(_to_ascii("0a.\u{05D0}").is_err());
    assert!(_to_ascii("0à.\u{05D0}").is_err());

    // Bidi chars may be punycode-encoded
    assert!(_to_ascii("xn--0ca24w").is_err());
}
<commit_msg>[idna] Add unit tests for punycode prefix edge cases<commit_after>use unicode_normalization::char::is_combining_mark;

/// https://github.com/servo/rust-url/issues/373
#[test]
fn test_punycode_prefix_with_length_check() {
    let config = idna::Config::default()
        .verify_dns_length(true)
        .check_hyphens(true)
        .use_std3_ascii_rules(true);

    assert!(config.to_ascii("xn--").is_err());
    assert!(config.to_ascii("xn---").is_err());
    assert!(config.to_ascii("xn-----").is_err());
    assert!(config.to_ascii("xn--.").is_err());
    assert!(config.to_ascii("xn--...").is_err());
    assert!(config.to_ascii(".xn--").is_err());
    assert!(config.to_ascii("...xn--").is_err());
    assert!(config.to_ascii("xn--.xn--").is_err());
    assert!(config.to_ascii("xn--.example.org").is_err());
}

/// https://github.com/servo/rust-url/issues/373
#[test]
fn test_punycode_prefix_without_length_check() {
    let config = idna::Config::default()
        .verify_dns_length(false)
        .check_hyphens(true)
        .use_std3_ascii_rules(true);

    assert_eq!(config.to_ascii("xn--").unwrap(), "");
    assert!(config.to_ascii("xn---").is_err());
    assert!(config.to_ascii("xn-----").is_err());
    assert_eq!(config.to_ascii("xn--.").unwrap(), ".");
    assert_eq!(config.to_ascii("xn--...").unwrap(), "...");
    assert_eq!(config.to_ascii(".xn--").unwrap(), ".");
    assert_eq!(config.to_ascii("...xn--").unwrap(), "...");
    assert_eq!(config.to_ascii("xn--.xn--").unwrap(), ".");
    assert_eq!(config.to_ascii("xn--.example.org").unwrap(), ".example.org");
}

#[test]
fn test_v5() {
    let config = idna::Config::default()
        .verify_dns_length(true)
        .use_std3_ascii_rules(true);

    // IdnaTest:784 蔏｡𑰺
    assert!(is_combining_mark('\u{11C3A}'));
    assert!(config.to_ascii("\u{11C3A}").is_err());
    assert!(config.to_ascii("\u{850f}.\u{11C3A}").is_err());
    assert!(config.to_ascii("\u{850f}\u{ff61}\u{11C3A}").is_err());
}

#[test]
fn test_v8_bidi_rules() {
    let config = idna::Config::default()
        .verify_dns_length(true)
        .use_std3_ascii_rules(true);

    assert_eq!(config.to_ascii("abc").unwrap(), "abc");
    assert_eq!(config.to_ascii("123").unwrap(), "123");
    assert_eq!(config.to_ascii("אבּג").unwrap(), "xn--kdb3bdf");
    assert_eq!(config.to_ascii("ابج").unwrap(), "xn--mgbcm");
    assert_eq!(config.to_ascii("abc.ابج").unwrap(), "abc.xn--mgbcm");
    assert_eq!(config.to_ascii("אבּג.ابج").unwrap(), "xn--kdb3bdf.xn--mgbcm");

    // Bidi domain names cannot start with digits
    assert!(config.to_ascii("0a.\u{05D0}").is_err());
    assert!(config.to_ascii("0à.\u{05D0}").is_err());

    // Bidi chars may be punycode-encoded
    assert!(config.to_ascii("xn--0ca24w").is_err());
}
<|endoftext|>


<commit_before>#![macro_escape]

#[macro_export]
macro_rules! object_struct(
	($name:ident) => (
		pub struct $name {
			ptr: ::id::Id,
		}

		impl ::runtime::Messageable for $name {
			unsafe fn as_ptr(&self) -> *::runtime::Object {
				self.ptr.as_ptr()
			}
		}

		impl ::id::FromId for $name {
			unsafe fn from_id(id: ::id::Id) -> $name {
				$name { ptr: id }
			}
		}

		impl ::foundation::INSObject for $name {
			fn class_name() -> ::id::ClassName<$name> {
				::id::ClassName::from_str(stringify!($name))
			}
		}

		impl ::std::clone::Clone for $name {
			fn clone(&self) -> $name {
				unsafe {
					::id::FromId::from_id(self.ptr.clone())
				}
			}
		}

		impl ::std::cmp::PartialEq for $name {
			fn eq(&self, other: &$name) -> bool {
				self.is_equal(other)
			}
		}

		impl ::std::cmp::Eq for $name { }

		impl<S: ::std::hash::Writer> ::std::hash::Hash<S> for $name {
			fn hash(&self, state: &mut S) {
				self.hash_code().hash(state);
			}
		}

		impl ::std::fmt::Show for $name {
			fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
				self.description().as_str().fmt(f)
			}
		}
	);
)
<commit_msg>Fixed some missing uses in object_struct macro.<commit_after>#![macro_escape]

#[macro_export]
macro_rules! object_struct(
	($name:ident) => (
		pub struct $name {
			ptr: ::id::Id,
		}

		impl ::runtime::Messageable for $name {
			unsafe fn as_ptr(&self) -> *::runtime::Object {
				use runtime::Messageable;
				self.ptr.as_ptr()
			}
		}

		impl ::id::FromId for $name {
			unsafe fn from_id(id: ::id::Id) -> $name {
				$name { ptr: id }
			}
		}

		impl ::foundation::INSObject for $name {
			fn class_name() -> ::id::ClassName<$name> {
				::id::ClassName::from_str(stringify!($name))
			}
		}

		impl ::std::clone::Clone for $name {
			fn clone(&self) -> $name {
				unsafe {
					::id::FromId::from_id(self.ptr.clone())
				}
			}
		}

		impl ::std::cmp::PartialEq for $name {
			fn eq(&self, other: &$name) -> bool {
				use foundation::INSObject;
				self.is_equal(other)
			}
		}

		impl ::std::cmp::Eq for $name { }

		impl<S: ::std::hash::Writer> ::std::hash::Hash<S> for $name {
			fn hash(&self, state: &mut S) {
				self.hash_code().hash(state);
			}
		}

		impl ::std::fmt::Show for $name {
			fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
				use foundation::{INSObject, INSString};
				self.description().as_str().fmt(f)
			}
		}
	);
)
<|endoftext|>


<commit_before>//! General purpose state transition operator.
use std::hash::Hash;
use std::collections::HashMap;

use ::{Data, ExchangeData};
use dataflow::{Stream, Scope};
use dataflow::operators::generic::unary::Unary;
use dataflow::channels::pact::Exchange;

/// Generic state-transition machinery: each key has a state, and receives a sequence of events.
/// Events are applied in time-order, but no other promises are made. Each state transition can
/// produce output, which is sent.
///
/// `state_machine` will buffer inputs if earlier inputs may still arrive. it will directly apply
/// updates for the current time reflected in the notificator, though. In the case of partially
/// ordered times, the only guarantee is that updates are not applied out of order, not that there
/// is some total order on times respecting the total order (updates may be interleaved).

/// Provides the `state_machine` method.
pub trait StateMachine<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> {
    /// Tracks a state for each presented key, using user-supplied state transition logic.
    ///
    /// The transition logic `fold` may mutate the state, and produce both output records and
    /// a `bool` indicating that it is appropriate to deregister the state, cleaning up once
    /// the state is no longer helpful.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Map, Inspect};
    /// use timely::dataflow::operators::aggregation::StateMachine;
    ///
    /// timely::example(|scope| {
    ///
    ///     // these results happen to be right, but aren't guaranteed.
    ///     // the system is at liberty to re-order within a timestamp.
    ///     let result = vec![(0,0), (0,2), (0,6), (0,12), (0,20),
    ///                       (1,1), (1,4), (1,9), (1,16), (1,25)];
    ///
    ///         (0..10).to_stream(scope)
    ///                .map(|x| (x % 2, x))
    ///                .state_machine(
    ///                    |_key, val, agg| { *agg += val; (false, Some((*_key, *agg))) },
    ///                    |key| *key as u64
    ///                )
    ///                .inspect(move |x| assert!(result.contains(x)));
    /// });
    /// ```
    fn state_machine<
        R: Data,                                    // output type
        D: Default+'static,                         // per-key state (data)
        I: IntoIterator<Item=R>,                    // type of output iterator
        F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
        H: Fn(&K)->u64+'static,                     // "hash" function for keys
    >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq ;
}

impl<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> StateMachine<S, K, V> for Stream<S, (K, V)> {
    fn state_machine<
            R: Data,                                    // output type
            D: Default+'static,                         // per-key state (data)
            I: IntoIterator<Item=R>,                    // type of output iterator
            F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
            H: Fn(&K)->u64+'static,                     // "hash" function for keys
        >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq {

        let mut pending = HashMap::new();   // times -> (keys -> state)
        let mut states = HashMap::new();    // keys -> state

        self.unary_notify(Exchange::new(move |&(ref k, _)| hash(k)), "StateMachine", vec![], move |input, output, notificator| {

            // stash each input and request a notification when ready
            input.for_each(|time, data| {
                // stash if not time yet
                if notificator.frontier(0).less_than(time.time()) {
                    pending.entry(time.time().clone()).or_insert_with(Vec::new).extend(data.drain(..));
                    notificator.notify_at(time.retain());
                }
                else {
                    // else we can process immediately
                    let mut session = output.session(&time);
                    for (key, val) in data.drain(..) {
                        let (remove, output) = {
                            let state = states.entry(key.clone()).or_insert_with(Default::default);
                            fold(&key, val, state)
                        };
                        if remove { states.remove(&key); }
                        session.give_iterator(output.into_iter());
                    }
                }
            });

            // go through each time with data, process each (key, val) pair.
            notificator.for_each(|time,_,_| {
                if let Some(pend) = pending.remove(time.time()) {
                    let mut session = output.session(&time);
                    for (key, val) in pend {
                        let (remove, output) = {
                            let state = states.entry(key.clone()).or_insert_with(Default::default);
                            fold(&key, val, state)
                        };
                        if remove { states.remove(&key); }
                        session.give_iterator(output.into_iter());
                    }
                }
            });
        })
    }
}
<commit_msg>Change state_machine operator to process data in-order<commit_after>//! General purpose state transition operator.
use std::hash::Hash;
use std::collections::HashMap;

use ::{Data, ExchangeData};
use dataflow::{Stream, Scope};
use dataflow::operators::generic::unary::Unary;
use dataflow::channels::pact::Exchange;

/// Generic state-transition machinery: each key has a state, and receives a sequence of events.
/// Events are applied in time-order, but no other promises are made. Each state transition can
/// produce output, which is sent.
///
/// `state_machine` will buffer inputs if earlier inputs may still arrive. it will directly apply
/// updates for the current time reflected in the notificator, though. In the case of partially
/// ordered times, the only guarantee is that updates are not applied out of order, not that there
/// is some total order on times respecting the total order (updates may be interleaved).

/// Provides the `state_machine` method.
pub trait StateMachine<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> {
    /// Tracks a state for each presented key, using user-supplied state transition logic.
    ///
    /// The transition logic `fold` may mutate the state, and produce both output records and
    /// a `bool` indicating that it is appropriate to deregister the state, cleaning up once
    /// the state is no longer helpful.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Map, Inspect};
    /// use timely::dataflow::operators::aggregation::StateMachine;
    ///
    /// timely::example(|scope| {
    ///
    ///     // these results happen to be right, but aren't guaranteed.
    ///     // the system is at liberty to re-order within a timestamp.
    ///     let result = vec![(0,0), (0,2), (0,6), (0,12), (0,20),
    ///                       (1,1), (1,4), (1,9), (1,16), (1,25)];
    ///
    ///         (0..10).to_stream(scope)
    ///                .map(|x| (x % 2, x))
    ///                .state_machine(
    ///                    |_key, val, agg| { *agg += val; (false, Some((*_key, *agg))) },
    ///                    |key| *key as u64
    ///                )
    ///                .inspect(move |x| assert!(result.contains(x)));
    /// });
    /// ```
    fn state_machine<
        R: Data,                                    // output type
        D: Default+'static,                         // per-key state (data)
        I: IntoIterator<Item=R>,                    // type of output iterator
        F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
        H: Fn(&K)->u64+'static,                     // "hash" function for keys
    >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq ;
}

impl<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> StateMachine<S, K, V> for Stream<S, (K, V)> {
    fn state_machine<
            R: Data,                                    // output type
            D: Default+'static,                         // per-key state (data)
            I: IntoIterator<Item=R>,                    // type of output iterator
            F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
            H: Fn(&K)->u64+'static,                     // "hash" function for keys
        >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq {

        let mut pending = HashMap::new();   // times -> (keys -> state)
        let mut states = HashMap::new();    // keys -> state

        self.unary_notify(Exchange::new(move |&(ref k, _)| hash(k)), "StateMachine", vec![], move |input, output, notificator| {

            // stash each input and request a notification when ready
            input.for_each(|time, data| {
                // Unconditionally stash data as `state_machine` requires data to be folded in-order.
                // Processing here can violate this invariant.
                pending.entry(time.time().clone()).or_insert_with(Vec::new).extend(data.drain(..));
                notificator.notify_at(time.retain());
            });

            // go through each time with data, process each (key, val) pair.
            notificator.for_each(|time,_,_| {
                if let Some(pend) = pending.remove(time.time()) {
                    let mut session = output.session(&time);
                    for (key, val) in pend {
                        let (remove, output) = {
                            let state = states.entry(key.clone()).or_insert_with(Default::default);
                            fold(&key, val, state)
                        };
                        if remove { states.remove(&key); }
                        session.give_iterator(output.into_iter());
                    }
                }
            });
        })
    }
}
<|endoftext|>


<commit_before>//! Brainfuck language interpreter

#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .arg(Arg::with_name("delay")
            .long("delay")
            .takes_value(true)
            .help("Delays execution of each instruction by this amount in ms")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let delay: u64 = if let Some(delay_str) = args.value_of("delay") {
        delay_str.parse().unwrap_or_else(|e: std::num::ParseIntError| exit_with_error!("Invalid delay: {}", e))
    } else {
        0
    };

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode, delay);
}

fn interpret(program: Vec<char>, debug: bool, delay: u64) {
    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    buffer[p] = 0;
                }
                else {
                    buffer[p] = chr.unwrap().expect("Could not read input");
                }
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{{\"lastInstructionIndex\": {}, \"lastInstruction\": \"{}\", \"currentPointer\": {}, \"memory\": \"{}\"}}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }

        thread::sleep(Duration::from_millis(delay));
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<commit_msg>Failed attempt to speed up interpreter by caching the last position of a jump<commit_after>//! Brainfuck language interpreter

#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .arg(Arg::with_name("delay")
            .long("delay")
            .takes_value(true)
            .help("Delays execution of each instruction by this amount in ms")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let delay: u64 = if let Some(delay_str) = args.value_of("delay") {
        delay_str.parse().unwrap_or_else(|e: std::num::ParseIntError| exit_with_error!("Invalid delay: {}", e))
    } else {
        0
    };

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode, delay);
}

fn interpret(program: Vec<char>, debug: bool, delay: u64) {
    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    // Stack of [ instructions so jumping backwards is super fast
    // The capacity is an estimate of what the typical maximum amount of nesting will be present
    // in a brainfuck program. If this is high enough, there will never be any allocation in the
    // stack after initialization
    let mut jump_stack = VecDeque::with_capacity(15);
    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    buffer[p] = 0;
                }
                else {
                    buffer[p] = chr.unwrap().expect("Could not read input");
                }
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1);
                }
                jump_stack.push_back(i);
            },
            ']' => {
                if buffer[p] != 0 {
                    i = *jump_stack.back()
                        .expect(&format!("Mismatched jump instructions at position {}", i));
                }
                else {
                    jump_stack.pop_back()
                        .expect(&format!("Mismatched jump instructions at position {}", i));
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{{\"lastInstructionIndex\": {}, \"lastInstruction\": \"{}\", \"currentPointer\": {}, \"memory\": \"{}\"}}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }

        thread::sleep(Duration::from_millis(delay));
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<|endoftext|>