<commit_before>use std::io::Read;
use std::marker::PhantomData;

use crate::{
    context::{Has, HasMut},
    GameError, GameResult,
};

use super::{
    context::GraphicsContext,
    gpu::{
        arc::{ArcBindGroup, ArcBindGroupLayout, ArcBuffer, ArcShaderModule},
        bind_group::BindGroupBuilder,
    },
    image::Image,
    sampler::Sampler,
};
use crevice::std140::Std140;
use wgpu::util::DeviceExt;

#[derive(Debug, PartialEq, Eq)]
enum ShaderSource<'a> {
    None,
    Path(&'a str),
    Code(&'a str),
}

/// Builder pattern for assembling shaders.
#[derive(Debug)]
pub struct ShaderBuilder<'a> {
    fs: ShaderSource<'a>,
    vs: ShaderSource<'a>,
}

impl<'a> ShaderBuilder<'a> {
    /// Create a new builder with no associated shader code.
    pub fn new_wgsl() -> Self {
        ShaderBuilder {
            fs: ShaderSource::None,
            vs: ShaderSource::None,
        }
    }

    /// Use this wgsl shader code for the fragment shader.
    pub fn fragment_code(self, source: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Code(source),
            vs: self.vs,
        }
    }
    /// Use this wgsl code resource path for the fragment shader.
    pub fn fragment_path(self, path: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Path(path),
            vs: self.vs,
        }
    }

    /// Use this wgsl shader code for the vertex shader.
    pub fn vertex_code(self, source: &'a str) -> Self {
        ShaderBuilder {
            fs: self.vs,
            vs: ShaderSource::Code(source),
        }
    }

    /// Use this wgsl code resource path for the vertex shader.
    pub fn vertex_path(self, path: &'a str) -> Self {
        ShaderBuilder {
            fs: self.vs,
            vs: ShaderSource::Path(path),
        }
    }

    /// Use this wgsl code as both a vertex and fragment shader.
    pub fn combined_code(self, source: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Code(source),
            vs: ShaderSource::Code(source),
        }
    }

    /// Use a single wgsl resource as both a vertex and fragment shader.
    pub fn combined_path(self, path: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Path(path),
            vs: ShaderSource::Path(path),
        }
    }

    /// Create a Shader from the builder.
    pub fn build(self, gfx: &impl Has<GraphicsContext>) -> GameResult<Shader> {
        let gfx = gfx.retrieve();
        let load = |s: &str| {
            Some(ArcShaderModule::new(gfx.wgpu.device.create_shader_module(
                wgpu::ShaderModuleDescriptor {
                    label: None,
                    source: wgpu::ShaderSource::Wgsl(s.into()),
                },
            )))
        };
        let load_resource = |path: &str| -> GameResult<Option<ArcShaderModule>> {
            let mut encoded = Vec::new();
            _ = gfx.fs.open(path)?.read_to_end(&mut encoded)?;
            Ok(load(
                &String::from_utf8(encoded).map_err(GameError::ShaderEncodingError)?,
            ))
        };
        let load_any = |source| -> GameResult<Option<ArcShaderModule>> {
            Ok(match source {
                ShaderSource::Code(source) => load(source),
                ShaderSource::Path(source) => load_resource(source)?,
                ShaderSource::None => None,
            })
        };
        Ok(if self.vs == self.fs {
            let module = load_any(self.vs)?;
            Shader {
                vs_module: module.clone(),
                fs_module: module,
            }
        } else {
            Shader {
                vs_module: load_any(self.vs)?,
                fs_module: load_any(self.fs)?,
            }
        })
    }
}

/// A custom shader that can be used to render with shader effects.
///
/// The shader may have a user specified vertex module, fragment module, both,
/// or neither. The fragment module entry point must be named fs_main. The
/// vertex module entry point must be named vs_main. The vertex module must
/// have an output of type
/// ```wgsl
/// struct VertexOutput {
///     @builtin(position) position: vec4<f32>,
///     @location(0) uv: vec2<f32>,
///     @location(1) color: vec4<f32>,
/// }
/// ```
/// if the fragment module is left unspecified (default).
///
/// Produce a Shader using [ShaderBuilder].
///
/// Adapted from the `shader.rs` example:
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// #[derive(AsStd140)]
/// struct Dim {
///     rate: f32,
/// }
///
/// struct MainState {}
///
/// impl event::EventHandler for MainState {
/// #   fn update(&mut self, _ctx: &mut Context) -> Result<(), GameError> { Ok(()) }
///     fn draw(&mut self, ctx: &mut Context) -> GameResult {
///         let mut canvas = graphics::Canvas::from_frame(ctx, Color::BLACK);
///         let dim = Dim { rate: 0.5 };
///         // NOTE: This is for simplicity; do not recreate your shader every frame like this!
///         //       For more info look at the full example.
///         let shader = ShaderBuilder::new_wgsl()
///             .fragment_code(include_str!("../../resources/dimmer.wgsl"))
///             .build(&mut ctx.gfx);
///         let params = ShaderParamsBuilder::new(&dim).build(&mut ctx.gfx);
///         params.set_uniforms(ctx, &dim);
///
///         canvas.set_shader(shader);
///         canvas.set_shader_params(params);
///         // draw something...
///         canvas.finish(ctx)
///     }
///
///     /* ... */
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Shader {
    pub(crate) vs_module: Option<ArcShaderModule>,
    pub(crate) fs_module: Option<ArcShaderModule>,
}

pub use crevice::std140::AsStd140;

/// A builder for [ShaderParams]
#[derive(Debug)]
pub struct ShaderParamsBuilder<'a, Uniforms: AsStd140> {
    uniforms: &'a Uniforms,
    images: &'a [(&'a Image, Sampler)],
    images_vs_visible: bool,
}

impl<'a, Uniforms: AsStd140> ShaderParamsBuilder<'a, Uniforms> {
    /// Creates a new builder for [ShaderParams].
    ///
    /// # Arguments
    ///
    /// * `uniforms` - Initial uniforms.
    pub fn new(uniforms: &'a Uniforms) -> Self {
        ShaderParamsBuilder {
            uniforms,
            images: &[],
            images_vs_visible: false,
        }
    }

    /// Provides images to the shaders.
    ///
    /// # Arguments
    ///
    /// * `vs_visible` - If the images should also be visible to the vertex shader, rather
    ///    than just the fragment shader.
    pub fn images(self, images: &'a [(&'a Image, Sampler)], vs_visible: bool) -> Self {
        ShaderParamsBuilder {
            uniforms: self.uniforms,
            images,
            images_vs_visible: vs_visible,
        }
    }

    /// Produce a [ShaderParams] from the builder.
    pub fn build(self, gfx: &mut impl HasMut<GraphicsContext>) -> ShaderParams<Uniforms> {
        let gfx = gfx.retrieve_mut();
        let uniforms = ArcBuffer::new(gfx.wgpu.device.create_buffer_init(
            &wgpu::util::BufferInitDescriptor {
                label: None,
                usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
                contents: self.uniforms.as_std140().as_bytes(),
            },
        ));

        let mut builder = BindGroupBuilder::new();
        builder = builder.buffer(
            &uniforms,
            0,
            wgpu::ShaderStages::VERTEX_FRAGMENT,
            wgpu::BufferBindingType::Uniform,
            false,
            None,
        );

        let vis = if self.images_vs_visible {
            wgpu::ShaderStages::VERTEX_FRAGMENT
        } else {
            wgpu::ShaderStages::FRAGMENT
        };
        for (image, _) in self.images {
            builder = builder.image(&image.view, vis);
        }

        let samplers = self
            .images
            .iter()
            .map(|&(_, sampler)| gfx.sampler_cache.get(&gfx.wgpu.device, sampler))
            .collect::<Vec<_>>();
        for sampler in &samplers {
            builder = builder.sampler(sampler, vis);
        }

        let (bind_group, layout) = builder.create_uncached(&gfx.wgpu.device);

        ShaderParams {
            uniforms,
            layout,
            bind_group,
            _marker: PhantomData,
        }
    }
}

/// Parameters that can be passed to a custom shader, including uniforms, images, and samplers.
///
/// Create with [ShaderParamsBuilder].
///
/// These parameters are bound to group 3. With WGSL, for example,
/// ```rust,ignore
/// ggez::graphics::ShaderParams::new(ctx, &my_uniforms, &[&image1, &image2], &[sampler1])
/// ```
/// Corresponds to...
/// ```ignore
/// @group(3) @binding(0)
/// var<uniform> my_uniforms: MyUniforms;
/// @group(3) @binding(1)
/// var image1: texture_2d<f32>;
/// @group(3) @binding(2)
/// var image2: texture_2d<f32>;
/// @group(3) @binding(3)
/// var sampler1: sampler;
/// ```
#[derive(Debug, PartialEq, Eq)]
pub struct ShaderParams<Uniforms: AsStd140> {
    pub(crate) uniforms: ArcBuffer,
    pub(crate) layout: ArcBindGroupLayout,
    pub(crate) bind_group: ArcBindGroup,
    _marker: PhantomData<Uniforms>,
}

impl<Uniforms: AsStd140> ShaderParams<Uniforms> {
    /// Updates the uniform data.
    pub fn set_uniforms(&self, gfx: &impl Has<GraphicsContext>, uniforms: &Uniforms) {
        let gfx = gfx.retrieve();
        gfx.wgpu
            .queue
            .write_buffer(&self.uniforms, 0, uniforms.as_std140().as_bytes());
    }
}

impl<Uniforms: AsStd140> Clone for ShaderParams<Uniforms> {
    fn clone(&self) -> Self {
        Self {
            uniforms: self.uniforms.clone(),
            layout: self.layout.clone(),
            bind_group: self.bind_group.clone(),
            _marker: PhantomData,
        }
    }
}

pub use wgpu::{BlendComponent, BlendFactor, BlendOperation};

/// Describes the blend mode used when drawing images.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BlendMode {
    /// The blend mode for the color channels.
    pub color: BlendComponent,
    /// The blend mode for the alpha channel.
    pub alpha: BlendComponent,
}

impl BlendMode {
    /// When combining two fragments, add their values together, saturating
    /// at 1.0
    pub const ADD: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the source value from the
    /// destination value
    pub const SUBTRACT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::ReverseSubtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, add the value of the source times its
    /// alpha channel with the value of the destination multiplied by the inverse
    /// of the source alpha channel. Has the usual transparency effect: mixes the
    /// two colors using a fraction of each one specified by the alpha of the source.
    pub const ALPHA: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the destination color from a constant
    /// color using the source color as weight. Has an invert effect with the constant
    /// color as base and source color controlling displacement from the base color.
    /// A white source color and a white value results in plain invert. The output
    /// alpha is same as destination alpha.
    pub const INVERT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Constant,
            dst_factor: BlendFactor::Src,
            operation: BlendOperation::Subtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, multiply their values together (including alpha)
    pub const MULTIPLY: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Dst,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::DstAlpha,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the source value (including source alpha)
    pub const REPLACE: Self = BlendMode {
        color: wgpu::BlendState::REPLACE.color,
        alpha: wgpu::BlendState::REPLACE.alpha,
    };

    /// When combining two fragments, choose the lighter value
    pub const LIGHTEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Max,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the darker value
    pub const DARKEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Min,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When using premultiplied alpha, use this.
    ///
    /// You usually want to use this blend mode for drawing canvases
    /// containing semi-transparent imagery.
    /// For an explanation on this see: <https://github.com/ggez/ggez/issues/694#issuecomment-853724926>
    pub const PREMULTIPLIED: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::One,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };
}
<commit_msg>One more docs ShaderParameters example update<commit_after>use std::io::Read;
use std::marker::PhantomData;

use crate::{
    context::{Has, HasMut},
    GameError, GameResult,
};

use super::{
    context::GraphicsContext,
    gpu::{
        arc::{ArcBindGroup, ArcBindGroupLayout, ArcBuffer, ArcShaderModule},
        bind_group::BindGroupBuilder,
    },
    image::Image,
    sampler::Sampler,
};
use crevice::std140::Std140;
use wgpu::util::DeviceExt;

#[derive(Debug, PartialEq, Eq)]
enum ShaderSource<'a> {
    None,
    Path(&'a str),
    Code(&'a str),
}

/// Builder pattern for assembling shaders.
#[derive(Debug)]
pub struct ShaderBuilder<'a> {
    fs: ShaderSource<'a>,
    vs: ShaderSource<'a>,
}

impl<'a> ShaderBuilder<'a> {
    /// Create a new builder with no associated shader code.
    pub fn new_wgsl() -> Self {
        ShaderBuilder {
            fs: ShaderSource::None,
            vs: ShaderSource::None,
        }
    }

    /// Use this wgsl shader code for the fragment shader.
    pub fn fragment_code(self, source: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Code(source),
            vs: self.vs,
        }
    }
    /// Use this wgsl code resource path for the fragment shader.
    pub fn fragment_path(self, path: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Path(path),
            vs: self.vs,
        }
    }

    /// Use this wgsl shader code for the vertex shader.
    pub fn vertex_code(self, source: &'a str) -> Self {
        ShaderBuilder {
            fs: self.vs,
            vs: ShaderSource::Code(source),
        }
    }

    /// Use this wgsl code resource path for the vertex shader.
    pub fn vertex_path(self, path: &'a str) -> Self {
        ShaderBuilder {
            fs: self.vs,
            vs: ShaderSource::Path(path),
        }
    }

    /// Use this wgsl code as both a vertex and fragment shader.
    pub fn combined_code(self, source: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Code(source),
            vs: ShaderSource::Code(source),
        }
    }

    /// Use a single wgsl resource as both a vertex and fragment shader.
    pub fn combined_path(self, path: &'a str) -> Self {
        ShaderBuilder {
            fs: ShaderSource::Path(path),
            vs: ShaderSource::Path(path),
        }
    }

    /// Create a Shader from the builder.
    pub fn build(self, gfx: &impl Has<GraphicsContext>) -> GameResult<Shader> {
        let gfx = gfx.retrieve();
        let load = |s: &str| {
            Some(ArcShaderModule::new(gfx.wgpu.device.create_shader_module(
                wgpu::ShaderModuleDescriptor {
                    label: None,
                    source: wgpu::ShaderSource::Wgsl(s.into()),
                },
            )))
        };
        let load_resource = |path: &str| -> GameResult<Option<ArcShaderModule>> {
            let mut encoded = Vec::new();
            _ = gfx.fs.open(path)?.read_to_end(&mut encoded)?;
            Ok(load(
                &String::from_utf8(encoded).map_err(GameError::ShaderEncodingError)?,
            ))
        };
        let load_any = |source| -> GameResult<Option<ArcShaderModule>> {
            Ok(match source {
                ShaderSource::Code(source) => load(source),
                ShaderSource::Path(source) => load_resource(source)?,
                ShaderSource::None => None,
            })
        };
        Ok(if self.vs == self.fs {
            let module = load_any(self.vs)?;
            Shader {
                vs_module: module.clone(),
                fs_module: module,
            }
        } else {
            Shader {
                vs_module: load_any(self.vs)?,
                fs_module: load_any(self.fs)?,
            }
        })
    }
}

/// A custom shader that can be used to render with shader effects.
///
/// The shader may have a user specified vertex module, fragment module, both,
/// or neither. The fragment module entry point must be named fs_main. The
/// vertex module entry point must be named vs_main. The vertex module must
/// have an output of type
/// ```wgsl
/// struct VertexOutput {
///     @builtin(position) position: vec4<f32>,
///     @location(0) uv: vec2<f32>,
///     @location(1) color: vec4<f32>,
/// }
/// ```
/// if the fragment module is left unspecified (default).
///
/// Produce a Shader using [ShaderBuilder].
///
/// Adapted from the `shader.rs` example:
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// #[derive(AsStd140)]
/// struct Dim {
///     rate: f32,
/// }
///
/// struct MainState {}
///
/// impl event::EventHandler for MainState {
/// #   fn update(&mut self, _ctx: &mut Context) -> Result<(), GameError> { Ok(()) }
///     fn draw(&mut self, ctx: &mut Context) -> GameResult {
///         let mut canvas = graphics::Canvas::from_frame(ctx, Color::BLACK);
///         let dim = Dim { rate: 0.5 };
///         // NOTE: This is for simplicity; do not recreate your shader every frame like this!
///         //       For more info look at the full example.
///         let shader = ShaderBuilder::new_wgsl()
///             .fragment_code(include_str!("../../resources/dimmer.wgsl"))
///             .build(&mut ctx.gfx);
///         let params = ShaderParamsBuilder::new(&dim).build(&mut ctx.gfx);
///         params.set_uniforms(ctx, &dim);
///
///         canvas.set_shader(shader);
///         canvas.set_shader_params(params);
///         // draw something...
///         canvas.finish(ctx)
///     }
///
///     /* ... */
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Shader {
    pub(crate) vs_module: Option<ArcShaderModule>,
    pub(crate) fs_module: Option<ArcShaderModule>,
}

pub use crevice::std140::AsStd140;

/// A builder for [ShaderParams]
#[derive(Debug)]
pub struct ShaderParamsBuilder<'a, Uniforms: AsStd140> {
    uniforms: &'a Uniforms,
    images: &'a [(&'a Image, Sampler)],
    images_vs_visible: bool,
}

impl<'a, Uniforms: AsStd140> ShaderParamsBuilder<'a, Uniforms> {
    /// Creates a new builder for [ShaderParams].
    ///
    /// # Arguments
    ///
    /// * `uniforms` - Initial uniforms.
    pub fn new(uniforms: &'a Uniforms) -> Self {
        ShaderParamsBuilder {
            uniforms,
            images: &[],
            images_vs_visible: false,
        }
    }

    /// Provides images to the shaders.
    ///
    /// # Arguments
    ///
    /// * `vs_visible` - If the images should also be visible to the vertex shader, rather
    ///    than just the fragment shader.
    pub fn images(self, images: &'a [(&'a Image, Sampler)], vs_visible: bool) -> Self {
        ShaderParamsBuilder {
            uniforms: self.uniforms,
            images,
            images_vs_visible: vs_visible,
        }
    }

    /// Produce a [ShaderParams] from the builder.
    pub fn build(self, gfx: &mut impl HasMut<GraphicsContext>) -> ShaderParams<Uniforms> {
        let gfx = gfx.retrieve_mut();
        let uniforms = ArcBuffer::new(gfx.wgpu.device.create_buffer_init(
            &wgpu::util::BufferInitDescriptor {
                label: None,
                usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
                contents: self.uniforms.as_std140().as_bytes(),
            },
        ));

        let mut builder = BindGroupBuilder::new();
        builder = builder.buffer(
            &uniforms,
            0,
            wgpu::ShaderStages::VERTEX_FRAGMENT,
            wgpu::BufferBindingType::Uniform,
            false,
            None,
        );

        let vis = if self.images_vs_visible {
            wgpu::ShaderStages::VERTEX_FRAGMENT
        } else {
            wgpu::ShaderStages::FRAGMENT
        };
        for (image, _) in self.images {
            builder = builder.image(&image.view, vis);
        }

        let samplers = self
            .images
            .iter()
            .map(|&(_, sampler)| gfx.sampler_cache.get(&gfx.wgpu.device, sampler))
            .collect::<Vec<_>>();
        for sampler in &samplers {
            builder = builder.sampler(sampler, vis);
        }

        let (bind_group, layout) = builder.create_uncached(&gfx.wgpu.device);

        ShaderParams {
            uniforms,
            layout,
            bind_group,
            _marker: PhantomData,
        }
    }
}

/// Parameters that can be passed to a custom shader, including uniforms, images, and samplers.
///
/// Create with [ShaderParamsBuilder].
///
/// These parameters are bound to group 3. With WGSL, for example,
/// ```rust,ignore
/// ggez::graphics::ShaderParamsBuilder::new(&my_uniforms)
///     .images(&[(&image1, &sampler1), (&image2, &sampler2)], false)
///     .build(&mut ctx.gfx)
/// ```
/// Corresponds to...
/// ```ignore
/// @group(3) @binding(0)
/// var<uniform> my_uniforms: MyUniforms;
/// @group(3) @binding(1)
/// var image1: texture_2d<f32>;
/// @group(3) @binding(2)
/// var image2: texture_2d<f32>;
/// @group(3) @binding(3)
/// var sampler1: sampler;
/// @group(3) @binding(4)
/// var sampler2: sampler;
/// ```
#[derive(Debug, PartialEq, Eq)]
pub struct ShaderParams<Uniforms: AsStd140> {
    pub(crate) uniforms: ArcBuffer,
    pub(crate) layout: ArcBindGroupLayout,
    pub(crate) bind_group: ArcBindGroup,
    _marker: PhantomData<Uniforms>,
}

impl<Uniforms: AsStd140> ShaderParams<Uniforms> {
    /// Updates the uniform data.
    pub fn set_uniforms(&self, gfx: &impl Has<GraphicsContext>, uniforms: &Uniforms) {
        let gfx = gfx.retrieve();
        gfx.wgpu
            .queue
            .write_buffer(&self.uniforms, 0, uniforms.as_std140().as_bytes());
    }
}

impl<Uniforms: AsStd140> Clone for ShaderParams<Uniforms> {
    fn clone(&self) -> Self {
        Self {
            uniforms: self.uniforms.clone(),
            layout: self.layout.clone(),
            bind_group: self.bind_group.clone(),
            _marker: PhantomData,
        }
    }
}

pub use wgpu::{BlendComponent, BlendFactor, BlendOperation};

/// Describes the blend mode used when drawing images.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BlendMode {
    /// The blend mode for the color channels.
    pub color: BlendComponent,
    /// The blend mode for the alpha channel.
    pub alpha: BlendComponent,
}

impl BlendMode {
    /// When combining two fragments, add their values together, saturating
    /// at 1.0
    pub const ADD: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the source value from the
    /// destination value
    pub const SUBTRACT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::ReverseSubtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, add the value of the source times its
    /// alpha channel with the value of the destination multiplied by the inverse
    /// of the source alpha channel. Has the usual transparency effect: mixes the
    /// two colors using a fraction of each one specified by the alpha of the source.
    pub const ALPHA: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the destination color from a constant
    /// color using the source color as weight. Has an invert effect with the constant
    /// color as base and source color controlling displacement from the base color.
    /// A white source color and a white value results in plain invert. The output
    /// alpha is same as destination alpha.
    pub const INVERT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Constant,
            dst_factor: BlendFactor::Src,
            operation: BlendOperation::Subtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, multiply their values together (including alpha)
    pub const MULTIPLY: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Dst,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::DstAlpha,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the source value (including source alpha)
    pub const REPLACE: Self = BlendMode {
        color: wgpu::BlendState::REPLACE.color,
        alpha: wgpu::BlendState::REPLACE.alpha,
    };

    /// When combining two fragments, choose the lighter value
    pub const LIGHTEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Max,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the darker value
    pub const DARKEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Min,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When using premultiplied alpha, use this.
    ///
    /// You usually want to use this blend mode for drawing canvases
    /// containing semi-transparent imagery.
    /// For an explanation on this see: <https://github.com/ggez/ggez/issues/694#issuecomment-853724926>
    pub const PREMULTIPLIED: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::One,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };
}
<|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/. */

//! Timing functions.

use heartbeats;
use ipc_channel::ipc::{self, IpcReceiver};
use profile_traits::energy::{energy_interval_ms, read_energy_uj};
use profile_traits::time::{ProfilerCategory, ProfilerChan, ProfilerMsg, TimerMetadata};
use profile_traits::time::{TimerMetadataReflowType, TimerMetadataFrameType};
use std::borrow::ToOwned;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fs;
use std::io::{self, Write};
use std::path;
use std::time::Duration;
use std::{thread, f64};
use std_time::precise_time_ns;
use trace_dump::TraceDump;
use util::thread::spawn_named;
use util::time::duration_from_seconds;

pub trait Formattable {
    fn format(&self) -> String;
}

impl Formattable for Option<TimerMetadata> {
    fn format(&self) -> String {
        match *self {
            // TODO(cgaebel): Center-align in the format strings as soon as rustc supports it.
            Some(ref meta) => {
                let url = &*meta.url;
                let url = if url.len() > 30 {
                    &url[..30]
                } else {
                    url
                };
                let incremental = match meta.incremental {
                    TimerMetadataReflowType::Incremental => "    yes",
                    TimerMetadataReflowType::FirstReflow => "    no ",
                };
                let iframe = match meta.iframe {
                    TimerMetadataFrameType::RootWindow => "  yes",
                    TimerMetadataFrameType::IFrame => "  no ",
                };
                format!(" {:14} {:9} {:30}", incremental, iframe, url)
            },
            None =>
                format!(" {:14} {:9} {:30}", "    N/A", "  N/A", "             N/A")
        }
    }
}

impl Formattable for ProfilerCategory {
    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    fn format(&self) -> String {
        let padding = match *self {
            ProfilerCategory::LayoutStyleRecalc |
            ProfilerCategory::LayoutRestyleDamagePropagation |
            ProfilerCategory::LayoutNonIncrementalReset |
            ProfilerCategory::LayoutGeneratedContent |
            ProfilerCategory::LayoutDisplayListSorting |
            ProfilerCategory::LayoutFloatPlacementSpeculation |
            ProfilerCategory::LayoutMain |
            ProfilerCategory::LayoutStoreOverflow |
            ProfilerCategory::LayoutDispListBuild |
            ProfilerCategory::LayoutDamagePropagate |
            ProfilerCategory::PaintingPerTile |
            ProfilerCategory::PaintingPrepBuff => "+ ",
            ProfilerCategory::LayoutParallelWarmup |
            ProfilerCategory::LayoutSelectorMatch |
            ProfilerCategory::LayoutTreeBuilder |
            ProfilerCategory::LayoutTextShaping => "| + ",
            _ => ""
        };
        let name = match *self {
            ProfilerCategory::Compositing => "Compositing",
            ProfilerCategory::LayoutPerform => "Layout",
            ProfilerCategory::LayoutStyleRecalc => "Style Recalc",
            ProfilerCategory::LayoutTextShaping => "Text Shaping",
            ProfilerCategory::LayoutRestyleDamagePropagation => "Restyle Damage Propagation",
            ProfilerCategory::LayoutNonIncrementalReset => "Non-incremental reset (temporary)",
            ProfilerCategory::LayoutSelectorMatch => "Selector Matching",
            ProfilerCategory::LayoutTreeBuilder => "Tree Building",
            ProfilerCategory::LayoutDamagePropagate => "Damage Propagation",
            ProfilerCategory::LayoutDisplayListSorting => "Sorting Display List",
            ProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution",
            ProfilerCategory::LayoutFloatPlacementSpeculation => "Float Placement Speculation",
            ProfilerCategory::LayoutMain => "Primary Layout Pass",
            ProfilerCategory::LayoutStoreOverflow => "Store Overflow",
            ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
            ProfilerCategory::LayoutDispListBuild => "Display List Construction",
            ProfilerCategory::PaintingPerTile => "Painting Per Tile",
            ProfilerCategory::PaintingPrepBuff => "Buffer Prep",
            ProfilerCategory::Painting => "Painting",
            ProfilerCategory::ImageDecoding => "Image Decoding",
            ProfilerCategory::ImageSaving => "Image Saving",
            ProfilerCategory::ScriptAttachLayout => "Script Attach Layout",
            ProfilerCategory::ScriptConstellationMsg => "Script Constellation Msg",
            ProfilerCategory::ScriptDevtoolsMsg => "Script Devtools Msg",
            ProfilerCategory::ScriptDocumentEvent => "Script Document Event",
            ProfilerCategory::ScriptDomEvent => "Script Dom Event",
            ProfilerCategory::ScriptFileRead => "Script File Read",
            ProfilerCategory::ScriptImageCacheMsg => "Script Image Cache Msg",
            ProfilerCategory::ScriptInputEvent => "Script Input Event",
            ProfilerCategory::ScriptNetworkEvent => "Script Network Event",
            ProfilerCategory::ScriptPlannedNavigation => "Script Planned Navigation",
            ProfilerCategory::ScriptResize => "Script Resize",
            ProfilerCategory::ScriptEvent => "Script Event",
            ProfilerCategory::ScriptUpdateReplacedElement => "Script Update Replaced Element",
            ProfilerCategory::ScriptSetViewport => "Script Set Viewport",
            ProfilerCategory::ScriptTimerEvent => "Script Timer Event",
            ProfilerCategory::ScriptStylesheetLoad => "Script Stylesheet Load",
            ProfilerCategory::ScriptWebSocketEvent => "Script Web Socket Event",
            ProfilerCategory::ScriptWorkerEvent => "Script Worker Event",
            ProfilerCategory::ApplicationHeartbeat => "Application Heartbeat",
        };
        format!("{}{}", padding, name)
    }
}

type ProfilerBuckets = BTreeMap<(ProfilerCategory, Option<TimerMetadata>), Vec<f64>>;

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    pub port: IpcReceiver<ProfilerMsg>,
    buckets: ProfilerBuckets,
    pub last_msg: Option<ProfilerMsg>,
    trace: Option<TraceDump>,
}

impl Profiler {
    pub fn create(period: Option<f64>, file_path: Option<String>) -> ProfilerChan {
        let (chan, port) = ipc::channel().unwrap();
        match period {
            Some(period) => {
                let chan = chan.clone();
                spawn_named("Time profiler timer".to_owned(), move || {
                    loop {
                        thread::sleep(duration_from_seconds(period));
                        if chan.send(ProfilerMsg::Print).is_err() {
                            break;
                        }
                    }
                });
                // Spawn the time profiler.
                spawn_named("Time profiler".to_owned(), move || {
                    let trace = file_path.as_ref()
                        .map(path::Path::new)
                        .map(fs::File::create)
                        .map(|res| TraceDump::new(res.unwrap()));
                    let mut profiler = Profiler::new(port, trace);
                    profiler.start();
                });
            }
            None => {
                // No-op to handle messages when the time profiler is inactive.
                spawn_named("Time profiler".to_owned(), move || {
                    loop {
                        match port.recv() {
                            Err(_) | Ok(ProfilerMsg::Exit) => break,
                            _ => {}
                        }
                    }
                });
            }
        }
        heartbeats::init();
        let profiler_chan = ProfilerChan(chan);

        // only spawn the application-level profiler thread if its heartbeat is enabled
        let run_ap_thread = || {
            heartbeats::is_heartbeat_enabled(&ProfilerCategory::ApplicationHeartbeat)
        };
        if run_ap_thread() {
            let profiler_chan = profiler_chan.clone();
            // min of 1 heartbeat/sec, max of 20 should provide accurate enough power/energy readings
            // waking up more frequently allows the thread to end faster on exit
            const SLEEP_MS: u32 = 10;
            const MIN_ENERGY_INTERVAL_MS: u32 = 50;
            const MAX_ENERGY_INTERVAL_MS: u32 = 1000;
            let interval_ms = enforce_range(MIN_ENERGY_INTERVAL_MS, MAX_ENERGY_INTERVAL_MS, energy_interval_ms());
            let loop_count: u32 = (interval_ms as f32 / SLEEP_MS as f32).ceil() as u32;
            spawn_named("Application heartbeat profiler".to_owned(), move || {
                let mut start_time = precise_time_ns();
                let mut start_energy = read_energy_uj();
                loop {
                    for _ in 0..loop_count {
                        if run_ap_thread() {
                            thread::sleep(Duration::from_millis(SLEEP_MS as u64))
                        } else {
                            return
                        }
                    }
                    let end_time = precise_time_ns();
                    let end_energy = read_energy_uj();
                    // send using the inner channel
                    // (using ProfilerChan.send() forces an unwrap and sometimes panics for this background profiler)
                    let ProfilerChan(ref c) = profiler_chan;
                    match c.send(ProfilerMsg::Time((ProfilerCategory::ApplicationHeartbeat, None),
                                                   (start_time, end_time),
                                                   (start_energy, end_energy))) {
                        Ok(_) => {},
                        Err(_) => return,
                    };
                    start_time = end_time;
                    start_energy = end_energy;
                }
            });
        }

        profiler_chan
    }

    pub fn new(port: IpcReceiver<ProfilerMsg>, trace: Option<TraceDump>) -> Profiler {
        Profiler {
            port: port,
            buckets: BTreeMap::new(),
            last_msg: None,
            trace: trace,
        }
    }

    pub fn start(&mut self) {
        while let Ok(msg) = self.port.recv() {
           if !self.handle_msg(msg) {
               break
           }
        }
    }

    fn find_or_insert(&mut self, k: (ProfilerCategory, Option<TimerMetadata>), t: f64) {
        match self.buckets.get_mut(&k) {
            None => {},
            Some(v) => { v.push(t); return; },
        }

        self.buckets.insert(k, vec!(t));
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) -> bool {
        match msg.clone() {
            ProfilerMsg::Time(k, t, e) => {
                heartbeats::maybe_heartbeat(&k.0, t.0, t.1, e.0, e.1);
                if let Some(ref mut trace) = self.trace {
                    trace.write_one(&k, t, e);
                }
                let ms = (t.1 - t.0) as f64 / 1000000f64;
                self.find_or_insert(k, ms);
            },
            ProfilerMsg::Print => if let Some(ProfilerMsg::Time(..)) = self.last_msg {
                // only print if more data has arrived since the last printout
                self.print_buckets();
            },
            ProfilerMsg::Exit => {
                heartbeats::cleanup();
                return false;
            },
        };
        self.last_msg = Some(msg);
        true
    }

    fn print_buckets(&mut self) {
        let stdout = io::stdout();
        let mut lock = stdout.lock();

        writeln!(&mut lock, "{:35} {:14} {:9} {:30} {:15} {:15} {:-15} {:-15} {:-15}",
                 "_category_", "_incremental?_", "_iframe?_",
                 "            _url_", "    _mean (ms)_", "  _median (ms)_",
                 "     _min (ms)_", "     _max (ms)_", "      _events_").unwrap();
        for (&(ref category, ref meta), ref mut data) in &mut self.buckets {
            data.sort_by(|a, b| {
                if a < b {
                    Ordering::Less
                } else {
                    Ordering::Greater
                }
            });
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, min, max) =
                    (data.iter().sum::<f64>() / (data_len as f64),
                     data[data_len / 2],
                     data.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
                     data.iter().fold(-f64::INFINITY, |a, &b| a.max(b)));
                writeln!(&mut lock, "{:-35}{} {:15.4} {:15.4} {:15.4} {:15.4} {:15}",
                         category.format(), meta.format(), mean, median, min, max,
                         data_len).unwrap();
            }
        }
        writeln!(&mut lock, "").unwrap();
    }
}

fn enforce_range<T>(min: T, max: T, value: T) -> T where T: Ord {
    assert!(min <= max);
    match value.cmp(&max) {
        Ordering::Equal | Ordering::Greater => max,
        Ordering::Less => {
            match value.cmp(&min) {
                Ordering::Equal | Ordering::Less => min,
                Ordering::Greater => value,
            }
        },
    }
}
<commit_msg>Make --profile-trace-path work without -p<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/. */

//! Timing functions.

use heartbeats;
use ipc_channel::ipc::{self, IpcReceiver};
use profile_traits::energy::{energy_interval_ms, read_energy_uj};
use profile_traits::time::{ProfilerCategory, ProfilerChan, ProfilerMsg, TimerMetadata};
use profile_traits::time::{TimerMetadataReflowType, TimerMetadataFrameType};
use std::borrow::ToOwned;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fs;
use std::io::{self, Write};
use std::path;
use std::time::Duration;
use std::{thread, f64};
use std_time::precise_time_ns;
use trace_dump::TraceDump;
use util::thread::spawn_named;
use util::time::duration_from_seconds;

pub trait Formattable {
    fn format(&self) -> String;
}

impl Formattable for Option<TimerMetadata> {
    fn format(&self) -> String {
        match *self {
            // TODO(cgaebel): Center-align in the format strings as soon as rustc supports it.
            Some(ref meta) => {
                let url = &*meta.url;
                let url = if url.len() > 30 {
                    &url[..30]
                } else {
                    url
                };
                let incremental = match meta.incremental {
                    TimerMetadataReflowType::Incremental => "    yes",
                    TimerMetadataReflowType::FirstReflow => "    no ",
                };
                let iframe = match meta.iframe {
                    TimerMetadataFrameType::RootWindow => "  yes",
                    TimerMetadataFrameType::IFrame => "  no ",
                };
                format!(" {:14} {:9} {:30}", incremental, iframe, url)
            },
            None =>
                format!(" {:14} {:9} {:30}", "    N/A", "  N/A", "             N/A")
        }
    }
}

impl Formattable for ProfilerCategory {
    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    fn format(&self) -> String {
        let padding = match *self {
            ProfilerCategory::LayoutStyleRecalc |
            ProfilerCategory::LayoutRestyleDamagePropagation |
            ProfilerCategory::LayoutNonIncrementalReset |
            ProfilerCategory::LayoutGeneratedContent |
            ProfilerCategory::LayoutDisplayListSorting |
            ProfilerCategory::LayoutFloatPlacementSpeculation |
            ProfilerCategory::LayoutMain |
            ProfilerCategory::LayoutStoreOverflow |
            ProfilerCategory::LayoutDispListBuild |
            ProfilerCategory::LayoutDamagePropagate |
            ProfilerCategory::PaintingPerTile |
            ProfilerCategory::PaintingPrepBuff => "+ ",
            ProfilerCategory::LayoutParallelWarmup |
            ProfilerCategory::LayoutSelectorMatch |
            ProfilerCategory::LayoutTreeBuilder |
            ProfilerCategory::LayoutTextShaping => "| + ",
            _ => ""
        };
        let name = match *self {
            ProfilerCategory::Compositing => "Compositing",
            ProfilerCategory::LayoutPerform => "Layout",
            ProfilerCategory::LayoutStyleRecalc => "Style Recalc",
            ProfilerCategory::LayoutTextShaping => "Text Shaping",
            ProfilerCategory::LayoutRestyleDamagePropagation => "Restyle Damage Propagation",
            ProfilerCategory::LayoutNonIncrementalReset => "Non-incremental reset (temporary)",
            ProfilerCategory::LayoutSelectorMatch => "Selector Matching",
            ProfilerCategory::LayoutTreeBuilder => "Tree Building",
            ProfilerCategory::LayoutDamagePropagate => "Damage Propagation",
            ProfilerCategory::LayoutDisplayListSorting => "Sorting Display List",
            ProfilerCategory::LayoutGeneratedContent => "Generated Content Resolution",
            ProfilerCategory::LayoutFloatPlacementSpeculation => "Float Placement Speculation",
            ProfilerCategory::LayoutMain => "Primary Layout Pass",
            ProfilerCategory::LayoutStoreOverflow => "Store Overflow",
            ProfilerCategory::LayoutParallelWarmup => "Parallel Warmup",
            ProfilerCategory::LayoutDispListBuild => "Display List Construction",
            ProfilerCategory::PaintingPerTile => "Painting Per Tile",
            ProfilerCategory::PaintingPrepBuff => "Buffer Prep",
            ProfilerCategory::Painting => "Painting",
            ProfilerCategory::ImageDecoding => "Image Decoding",
            ProfilerCategory::ImageSaving => "Image Saving",
            ProfilerCategory::ScriptAttachLayout => "Script Attach Layout",
            ProfilerCategory::ScriptConstellationMsg => "Script Constellation Msg",
            ProfilerCategory::ScriptDevtoolsMsg => "Script Devtools Msg",
            ProfilerCategory::ScriptDocumentEvent => "Script Document Event",
            ProfilerCategory::ScriptDomEvent => "Script Dom Event",
            ProfilerCategory::ScriptFileRead => "Script File Read",
            ProfilerCategory::ScriptImageCacheMsg => "Script Image Cache Msg",
            ProfilerCategory::ScriptInputEvent => "Script Input Event",
            ProfilerCategory::ScriptNetworkEvent => "Script Network Event",
            ProfilerCategory::ScriptPlannedNavigation => "Script Planned Navigation",
            ProfilerCategory::ScriptResize => "Script Resize",
            ProfilerCategory::ScriptEvent => "Script Event",
            ProfilerCategory::ScriptUpdateReplacedElement => "Script Update Replaced Element",
            ProfilerCategory::ScriptSetViewport => "Script Set Viewport",
            ProfilerCategory::ScriptTimerEvent => "Script Timer Event",
            ProfilerCategory::ScriptStylesheetLoad => "Script Stylesheet Load",
            ProfilerCategory::ScriptWebSocketEvent => "Script Web Socket Event",
            ProfilerCategory::ScriptWorkerEvent => "Script Worker Event",
            ProfilerCategory::ApplicationHeartbeat => "Application Heartbeat",
        };
        format!("{}{}", padding, name)
    }
}

type ProfilerBuckets = BTreeMap<(ProfilerCategory, Option<TimerMetadata>), Vec<f64>>;

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    pub port: IpcReceiver<ProfilerMsg>,
    buckets: ProfilerBuckets,
    pub last_msg: Option<ProfilerMsg>,
    trace: Option<TraceDump>,
}

impl Profiler {
    pub fn create(period: Option<f64>, file_path: Option<String>) -> ProfilerChan {
        let (chan, port) = ipc::channel().unwrap();
        if let Some(period) = period {
            let chan = chan.clone();
            spawn_named("Time profiler timer".to_owned(), move || {
                loop {
                    thread::sleep(duration_from_seconds(period));
                    if chan.send(ProfilerMsg::Print).is_err() {
                        break;
                    }
                }
            });
        }

        if period.is_some() || file_path.is_some() {
            // Spawn the time profiler.
            spawn_named("Time profiler".to_owned(), move || {
                let trace = file_path.as_ref()
                    .map(path::Path::new)
                    .map(fs::File::create)
                    .map(|res| TraceDump::new(res.unwrap()));
                let mut profiler = Profiler::new(port, trace);
                profiler.start();
            });
        } else {
            // No-op to handle messages when the time profiler is inactive.
            spawn_named("Time profiler".to_owned(), move || {
                loop {
                    match port.recv() {
                        Err(_) | Ok(ProfilerMsg::Exit) => break,
                        _ => {}
                    }
                }
            });
        }

        heartbeats::init();
        let profiler_chan = ProfilerChan(chan);

        // only spawn the application-level profiler thread if its heartbeat is enabled
        let run_ap_thread = || {
            heartbeats::is_heartbeat_enabled(&ProfilerCategory::ApplicationHeartbeat)
        };
        if run_ap_thread() {
            let profiler_chan = profiler_chan.clone();
            // min of 1 heartbeat/sec, max of 20 should provide accurate enough power/energy readings
            // waking up more frequently allows the thread to end faster on exit
            const SLEEP_MS: u32 = 10;
            const MIN_ENERGY_INTERVAL_MS: u32 = 50;
            const MAX_ENERGY_INTERVAL_MS: u32 = 1000;
            let interval_ms = enforce_range(MIN_ENERGY_INTERVAL_MS, MAX_ENERGY_INTERVAL_MS, energy_interval_ms());
            let loop_count: u32 = (interval_ms as f32 / SLEEP_MS as f32).ceil() as u32;
            spawn_named("Application heartbeat profiler".to_owned(), move || {
                let mut start_time = precise_time_ns();
                let mut start_energy = read_energy_uj();
                loop {
                    for _ in 0..loop_count {
                        if run_ap_thread() {
                            thread::sleep(Duration::from_millis(SLEEP_MS as u64))
                        } else {
                            return
                        }
                    }
                    let end_time = precise_time_ns();
                    let end_energy = read_energy_uj();
                    // send using the inner channel
                    // (using ProfilerChan.send() forces an unwrap and sometimes panics for this background profiler)
                    let ProfilerChan(ref c) = profiler_chan;
                    match c.send(ProfilerMsg::Time((ProfilerCategory::ApplicationHeartbeat, None),
                                                   (start_time, end_time),
                                                   (start_energy, end_energy))) {
                        Ok(_) => {},
                        Err(_) => return,
                    };
                    start_time = end_time;
                    start_energy = end_energy;
                }
            });
        }

        profiler_chan
    }

    pub fn new(port: IpcReceiver<ProfilerMsg>, trace: Option<TraceDump>) -> Profiler {
        Profiler {
            port: port,
            buckets: BTreeMap::new(),
            last_msg: None,
            trace: trace,
        }
    }

    pub fn start(&mut self) {
        while let Ok(msg) = self.port.recv() {
           if !self.handle_msg(msg) {
               break
           }
        }
    }

    fn find_or_insert(&mut self, k: (ProfilerCategory, Option<TimerMetadata>), t: f64) {
        match self.buckets.get_mut(&k) {
            None => {},
            Some(v) => { v.push(t); return; },
        }

        self.buckets.insert(k, vec!(t));
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) -> bool {
        match msg.clone() {
            ProfilerMsg::Time(k, t, e) => {
                heartbeats::maybe_heartbeat(&k.0, t.0, t.1, e.0, e.1);
                if let Some(ref mut trace) = self.trace {
                    trace.write_one(&k, t, e);
                }
                let ms = (t.1 - t.0) as f64 / 1000000f64;
                self.find_or_insert(k, ms);
            },
            ProfilerMsg::Print => if let Some(ProfilerMsg::Time(..)) = self.last_msg {
                // only print if more data has arrived since the last printout
                self.print_buckets();
            },
            ProfilerMsg::Exit => {
                heartbeats::cleanup();
                return false;
            },
        };
        self.last_msg = Some(msg);
        true
    }

    fn print_buckets(&mut self) {
        let stdout = io::stdout();
        let mut lock = stdout.lock();

        writeln!(&mut lock, "{:35} {:14} {:9} {:30} {:15} {:15} {:-15} {:-15} {:-15}",
                 "_category_", "_incremental?_", "_iframe?_",
                 "            _url_", "    _mean (ms)_", "  _median (ms)_",
                 "     _min (ms)_", "     _max (ms)_", "      _events_").unwrap();
        for (&(ref category, ref meta), ref mut data) in &mut self.buckets {
            data.sort_by(|a, b| {
                if a < b {
                    Ordering::Less
                } else {
                    Ordering::Greater
                }
            });
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, min, max) =
                    (data.iter().sum::<f64>() / (data_len as f64),
                     data[data_len / 2],
                     data.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
                     data.iter().fold(-f64::INFINITY, |a, &b| a.max(b)));
                writeln!(&mut lock, "{:-35}{} {:15.4} {:15.4} {:15.4} {:15.4} {:15}",
                         category.format(), meta.format(), mean, median, min, max,
                         data_len).unwrap();
            }
        }
        writeln!(&mut lock, "").unwrap();
    }
}

fn enforce_range<T>(min: T, max: T, value: T) -> T where T: Ord {
    assert!(min <= max);
    match value.cmp(&max) {
        Ordering::Equal | Ordering::Greater => max,
        Ordering::Less => {
            match value.cmp(&min) {
                Ordering::Equal | Ordering::Less => min,
                Ordering::Greater => value,
            }
        },
    }
}
<|endoftext|>


<commit_before>extern crate matrix;

use matrix::Matrix;

fn main() {
    let mut m = Matrix::from(&[
        &[1, 2, 3],
        &[4, 5, 6],
        &[7, 8, 9]
    ]);
    println!("M = {:?}", m);
    m[(1, 1)] = 10;
    println!("M[1, 1] = {}", m[(1, 1)]);
    println!("M = {:?}", m);
}<commit_msg>[fix] example code<commit_after>extern crate arrays;

use arrays::Array2D;

fn main() {
    let mut m = Array2D::from(&[
        &[1, 2, 3],
        &[4, 5, 6],
        &[0, 0, 0]
    ]);
    println!("M = {:?}", m);
    for i in 0..3 {
        m[(2, i)] = m[(0, i)] + m[(1, i)];
    }
    println!("M = {:?}", m);
}<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(use_extern_macros)]

#[macro_use]
extern crate tapioca;

infer_api!(httpbin, "https://raw.githubusercontent.com/OJFord/tapioca/master/tests/schemata/httpbin.yml");

use httpbin::basic_auth__user__hunter_2 as basic_auth;
use basic_auth::get::OpAuth::HttpBasic;

static USER: &str = "baz";

fn main() {
    let auth = httpbin::ServerAuth::new();

    match httpbin::ip::get(auth) {
        Ok(response) => match response.body() {
            httpbin::ip::get::OkBody::Status200(body) => println!("Your IP is {}", body.origin),
            _ => panic!(),
        },
        _ => println!("Failed to find IP address"),
    }

    let query = httpbin::post::post::QueryParams {
        echo: Some("echo me!".into()),
    };
    match httpbin::post::post(&query, auth) {
        Ok(response) => match response.body() {
            httpbin::post::post::OkBody::Status200(_) => assert!(true),
            _ => panic!(),
        },
        _ => panic!(),
    }

    let user_id = basic_auth::ResourceId_user::from_static(USER);
    let auth = HttpBasic((USER.into(), "hunter2".into()).into());
    let response = basic_auth::get(&user_id, auth.into());
    println!("Auth response: {:?}", response.body());
}
<commit_msg>Improve example as a demo<commit_after>#![feature(associated_consts)]
#![feature(use_extern_macros)]

#[macro_use]
extern crate tapioca;

infer_api!(httpbin, "https://raw.githubusercontent.com/OJFord/tapioca/master/tests/schemata/httpbin.yml");

use httpbin::basic_auth__user__hunter_2 as basic_auth;
use basic_auth::get::OpAuth::HttpBasic;

static USER: &str = "baz";

fn main() {
    let auth = httpbin::ServerAuth::new();

    match httpbin::ip::get(auth) {
        Ok(response) => match response.body() {
            httpbin::ip::get::OkBody::Status200(body) => println!("Your IP is {}", body.origin),
            _ => println!("httbin.org did something unexpected"),
        },
        Err(_) => println!("httpbin.org errored"),
    }

    let user_id = basic_auth::ResourceId_user::from_static(USER);
    let auth = HttpBasic((USER.into(), "hunter2".into()).into());
    match basic_auth::get(&user_id, auth.into()) {
        Ok(response) => match response.body() {
            basic_auth::get::OkBody::Status200(body) => if body.authenticated {
                println!("User '{}' authenticated OK!", body.user)
            } else {
                println!("Authentication failed for user '{}'!", body.user)
            },
            _ => println!("httbin.org did something unexpected"),
        },
        Err(_) => println!("httpbin.org errored"),
    }
}
<|endoftext|>


<commit_before>// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

macro_rules! impl_consensus_encoding {
    ($thing:ident, $($field:ident),+) => (
        impl<S: ::network::serialize::SimpleEncoder> ::network::encodable::ConsensusEncodable<S> for $thing {
            #[inline]
            fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
                $( try!(self.$field.consensus_encode(s)); )+
                Ok(())
            }
        }

        impl<D: ::network::serialize::SimpleDecoder> ::network::encodable::ConsensusDecodable<D> for $thing {
            #[inline]
            fn consensus_decode(d: &mut D) -> Result<$thing, D::Error> {
                use network::encodable::ConsensusDecodable;
                Ok($thing {
                    $( $field: try!(ConsensusDecodable::consensus_decode(d)), )+
                })
            }
        }
    );
}

macro_rules! impl_newtype_consensus_encoding {
    ($thing:ident) => (
        impl<S: ::network::serialize::SimpleEncoder> ::network::encodable::ConsensusEncodable<S> for $thing {
            #[inline]
            fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
                let &$thing(ref data) = self;
                data.consensus_encode(s)
            }
        }

        impl<D: ::network::serialize::SimpleDecoder> ::network::encodable::ConsensusDecodable<D> for $thing {
            #[inline]
            fn consensus_decode(d: &mut D) -> Result<$thing, D::Error> {
                Ok($thing(try!(ConsensusDecodable::consensus_decode(d))))
            }
        }
    );
}

macro_rules! impl_array_newtype {
    ($thing:ident, $ty:ty, $len:expr) => {
        impl $thing {
            #[inline]
            /// Converts the object to a raw pointer
            pub fn as_ptr(&self) -> *const $ty {
                let &$thing(ref dat) = self;
                dat.as_ptr()
            }

            #[inline]
            /// Converts the object to a mutable raw pointer
            pub fn as_mut_ptr(&mut self) -> *mut $ty {
                let &mut $thing(ref mut dat) = self;
                dat.as_mut_ptr()
            }

            #[inline]
            /// Returns the length of the object as an array
            pub fn len(&self) -> usize { $len }

            #[inline]
            /// Returns whether the object, as an array, is empty. Always false.
            pub fn is_empty(&self) -> bool { false }
        }

        impl<'a> From<&'a [$ty]> for $thing {
            fn from(data: &'a [$ty]) -> $thing {
                assert_eq!(data.len(), $len);
                unsafe {
                    use std::intrinsics::copy_nonoverlapping;
                    use std::mem;
                    let mut ret: $thing = mem::uninitialized();
                    copy_nonoverlapping(data.as_ptr(),
                                        ret.as_mut_ptr(),
                                        mem::size_of::<$thing>());
                    ret
                }
            }
        }

        impl ::std::ops::Index<usize> for $thing {
            type Output = $ty;

            #[inline]
            fn index(&self, index: usize) -> &$ty {
                let &$thing(ref dat) = self;
                &dat[index]
            }
        }

        impl_index_newtype!($thing, $ty);

        impl PartialEq for $thing {
            #[inline]
            fn eq(&self, other: &$thing) -> bool {
                &self[..] == &other[..]
            }
        }

        impl Eq for $thing {}

        impl PartialOrd for $thing {
            #[inline]
            fn partial_cmp(&self, other: &$thing) -> Option<::std::cmp::Ordering> {
                Some(self.cmp(&other))
            }
        }

        impl Ord for $thing {
            #[inline]
            fn cmp(&self, other: &$thing) -> ::std::cmp::Ordering {
                // manually implement comparison to get little-endian ordering
                // (we need this for our numeric types; non-numeric ones shouldn't
                // be ordered anyway except to put them in BTrees or whatever, and
                // they don't care how we order as long as we're consisistent).
                for i in 0..$len {
                    if self[$len - 1 - i] < other[$len - 1 - i] { return ::std::cmp::Ordering::Less; }
                    if self[$len - 1 - i] > other[$len - 1 - i] { return ::std::cmp::Ordering::Greater; }
                }
                ::std::cmp::Ordering::Equal
            }
        }

        #[cfg_attr(feature = "clippy", allow(expl_impl_clone_on_copy))] // we don't define the `struct`, we have to explicitly impl
        impl Clone for $thing {
            #[inline]
            fn clone(&self) -> $thing {
                $thing::from(&self[..])
            }
        }

        impl Copy for $thing {}

        impl ::std::hash::Hash for $thing {
            #[inline]
            fn hash<H>(&self, state: &mut H)
                where H: ::std::hash::Hasher
            {
                (&self[..]).hash(state);
            }

            fn hash_slice<H>(data: &[$thing], state: &mut H)
                where H: ::std::hash::Hasher
            {
                for d in data.iter() {
                    (&d[..]).hash(state);
                }
            }
        }

        impl ::rand::Rand for $thing {
            #[inline]
            fn rand<R: ::rand::Rng>(r: &mut R) -> $thing {
                $thing(::rand::Rand::rand(r))
            }
        }
    }
}

macro_rules! impl_array_newtype_encodable {
    ($thing:ident, $ty:ty, $len:expr) => {

        impl ::serde::Deserialize for $thing {
            fn deserialize<D>(d: &mut D) -> Result<$thing, D::Error>
                where D: ::serde::Deserializer
            {
                // We have to define the Visitor struct inside the function
                // to make it local ... what we really need is that it's
                // local to the macro, but this is Close Enough.
                struct Visitor {
                    marker: ::std::marker::PhantomData<$thing>,
                }
                impl ::serde::de::Visitor for Visitor {
                    type Value = $thing;

                    #[inline]
                    fn visit_seq<V>(&mut self, mut v: V) -> Result<$thing, V::Error>
                        where V: ::serde::de::SeqVisitor
                    {
                        unsafe {
                            use std::mem;
                            let mut ret: [$ty; $len] = mem::uninitialized();
                            for item in ret.iter_mut() {
                                *item = match try!(v.visit()) {
                                    Some(c) => c,
                                    None => return Err(::serde::de::Error::end_of_stream())
                                };
                            }
                            try!(v.end());
                            Ok($thing(ret))
                        }
                    }
                }

                // Begin actual function
                d.visit(Visitor { marker: ::std::marker::PhantomData })
            }
        }

        impl ::serde::Serialize for $thing {
            fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
                where S: ::serde::Serializer
            {
                let &$thing(ref dat) = self;
                (&dat[..]).serialize(s)
            }
        }
    }
}

macro_rules! impl_array_newtype_show {
    ($thing:ident) => {
        impl ::std::fmt::Debug for $thing {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                write!(f, concat!(stringify!($thing), "({:?})"), &self[..])
            }
        }
    }
}

macro_rules! impl_index_newtype {
    ($thing:ident, $ty:ty) => {
        impl ::std::ops::Index<::std::ops::Range<usize>> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, index: ::std::ops::Range<usize>) -> &[$ty] {
                &self.0[index]
            }
        }

        impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[$ty] {
                &self.0[index]
            }
        }

        impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[$ty] {
                &self.0[index]
            }
        }

        impl ::std::ops::Index<::std::ops::RangeFull> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, _: ::std::ops::RangeFull) -> &[$ty] {
                &self.0[..]
            }
        }

    }
}

macro_rules! display_from_debug {
    ($thing:ident) => {
        impl ::std::fmt::Display for $thing {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                ::std::fmt::Debug::fmt(self, f)
            }
        }
    }
}

<commit_msg>Fix argument to copy_nonoverlapping in internal_macros<commit_after>// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

macro_rules! impl_consensus_encoding {
    ($thing:ident, $($field:ident),+) => (
        impl<S: ::network::serialize::SimpleEncoder> ::network::encodable::ConsensusEncodable<S> for $thing {
            #[inline]
            fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
                $( try!(self.$field.consensus_encode(s)); )+
                Ok(())
            }
        }

        impl<D: ::network::serialize::SimpleDecoder> ::network::encodable::ConsensusDecodable<D> for $thing {
            #[inline]
            fn consensus_decode(d: &mut D) -> Result<$thing, D::Error> {
                use network::encodable::ConsensusDecodable;
                Ok($thing {
                    $( $field: try!(ConsensusDecodable::consensus_decode(d)), )+
                })
            }
        }
    );
}

macro_rules! impl_newtype_consensus_encoding {
    ($thing:ident) => (
        impl<S: ::network::serialize::SimpleEncoder> ::network::encodable::ConsensusEncodable<S> for $thing {
            #[inline]
            fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
                let &$thing(ref data) = self;
                data.consensus_encode(s)
            }
        }

        impl<D: ::network::serialize::SimpleDecoder> ::network::encodable::ConsensusDecodable<D> for $thing {
            #[inline]
            fn consensus_decode(d: &mut D) -> Result<$thing, D::Error> {
                Ok($thing(try!(ConsensusDecodable::consensus_decode(d))))
            }
        }
    );
}

macro_rules! impl_array_newtype {
    ($thing:ident, $ty:ty, $len:expr) => {
        impl $thing {
            #[inline]
            /// Converts the object to a raw pointer
            pub fn as_ptr(&self) -> *const $ty {
                let &$thing(ref dat) = self;
                dat.as_ptr()
            }

            #[inline]
            /// Converts the object to a mutable raw pointer
            pub fn as_mut_ptr(&mut self) -> *mut $ty {
                let &mut $thing(ref mut dat) = self;
                dat.as_mut_ptr()
            }

            #[inline]
            /// Returns the length of the object as an array
            pub fn len(&self) -> usize { $len }

            #[inline]
            /// Returns whether the object, as an array, is empty. Always false.
            pub fn is_empty(&self) -> bool { false }
        }

        impl<'a> From<&'a [$ty]> for $thing {
            fn from(data: &'a [$ty]) -> $thing {
                assert_eq!(data.len(), $len);
                unsafe {
                    use std::intrinsics::copy_nonoverlapping;
                    use std::mem;
                    let mut ret: $thing = mem::uninitialized();
                    copy_nonoverlapping(data.as_ptr(),
                                        ret.as_mut_ptr(),
                                        $len);
                    ret
                }
            }
        }

        impl ::std::ops::Index<usize> for $thing {
            type Output = $ty;

            #[inline]
            fn index(&self, index: usize) -> &$ty {
                let &$thing(ref dat) = self;
                &dat[index]
            }
        }

        impl_index_newtype!($thing, $ty);

        impl PartialEq for $thing {
            #[inline]
            fn eq(&self, other: &$thing) -> bool {
                &self[..] == &other[..]
            }
        }

        impl Eq for $thing {}

        impl PartialOrd for $thing {
            #[inline]
            fn partial_cmp(&self, other: &$thing) -> Option<::std::cmp::Ordering> {
                Some(self.cmp(&other))
            }
        }

        impl Ord for $thing {
            #[inline]
            fn cmp(&self, other: &$thing) -> ::std::cmp::Ordering {
                // manually implement comparison to get little-endian ordering
                // (we need this for our numeric types; non-numeric ones shouldn't
                // be ordered anyway except to put them in BTrees or whatever, and
                // they don't care how we order as long as we're consisistent).
                for i in 0..$len {
                    if self[$len - 1 - i] < other[$len - 1 - i] { return ::std::cmp::Ordering::Less; }
                    if self[$len - 1 - i] > other[$len - 1 - i] { return ::std::cmp::Ordering::Greater; }
                }
                ::std::cmp::Ordering::Equal
            }
        }

        #[cfg_attr(feature = "clippy", allow(expl_impl_clone_on_copy))] // we don't define the `struct`, we have to explicitly impl
        impl Clone for $thing {
            #[inline]
            fn clone(&self) -> $thing {
                $thing::from(&self[..])
            }
        }

        impl Copy for $thing {}

        impl ::std::hash::Hash for $thing {
            #[inline]
            fn hash<H>(&self, state: &mut H)
                where H: ::std::hash::Hasher
            {
                (&self[..]).hash(state);
            }

            fn hash_slice<H>(data: &[$thing], state: &mut H)
                where H: ::std::hash::Hasher
            {
                for d in data.iter() {
                    (&d[..]).hash(state);
                }
            }
        }

        impl ::rand::Rand for $thing {
            #[inline]
            fn rand<R: ::rand::Rng>(r: &mut R) -> $thing {
                $thing(::rand::Rand::rand(r))
            }
        }
    }
}

macro_rules! impl_array_newtype_encodable {
    ($thing:ident, $ty:ty, $len:expr) => {

        impl ::serde::Deserialize for $thing {
            fn deserialize<D>(d: &mut D) -> Result<$thing, D::Error>
                where D: ::serde::Deserializer
            {
                // We have to define the Visitor struct inside the function
                // to make it local ... what we really need is that it's
                // local to the macro, but this is Close Enough.
                struct Visitor {
                    marker: ::std::marker::PhantomData<$thing>,
                }
                impl ::serde::de::Visitor for Visitor {
                    type Value = $thing;

                    #[inline]
                    fn visit_seq<V>(&mut self, mut v: V) -> Result<$thing, V::Error>
                        where V: ::serde::de::SeqVisitor
                    {
                        unsafe {
                            use std::mem;
                            let mut ret: [$ty; $len] = mem::uninitialized();
                            for item in ret.iter_mut() {
                                *item = match try!(v.visit()) {
                                    Some(c) => c,
                                    None => return Err(::serde::de::Error::end_of_stream())
                                };
                            }
                            try!(v.end());
                            Ok($thing(ret))
                        }
                    }
                }

                // Begin actual function
                d.visit(Visitor { marker: ::std::marker::PhantomData })
            }
        }

        impl ::serde::Serialize for $thing {
            fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
                where S: ::serde::Serializer
            {
                let &$thing(ref dat) = self;
                (&dat[..]).serialize(s)
            }
        }
    }
}

macro_rules! impl_array_newtype_show {
    ($thing:ident) => {
        impl ::std::fmt::Debug for $thing {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                write!(f, concat!(stringify!($thing), "({:?})"), &self[..])
            }
        }
    }
}

macro_rules! impl_index_newtype {
    ($thing:ident, $ty:ty) => {
        impl ::std::ops::Index<::std::ops::Range<usize>> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, index: ::std::ops::Range<usize>) -> &[$ty] {
                &self.0[index]
            }
        }

        impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[$ty] {
                &self.0[index]
            }
        }

        impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[$ty] {
                &self.0[index]
            }
        }

        impl ::std::ops::Index<::std::ops::RangeFull> for $thing {
            type Output = [$ty];

            #[inline]
            fn index(&self, _: ::std::ops::RangeFull) -> &[$ty] {
                &self.0[..]
            }
        }

    }
}

macro_rules! display_from_debug {
    ($thing:ident) => {
        impl ::std::fmt::Display for $thing {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                ::std::fmt::Debug::fmt(self, f)
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::sync::Arc;
use builder::module;
use elements::{Module, FunctionType, ExportEntry, Internal, MemoryType, GlobalEntry, GlobalType,
	ValueType, InitExpr, TableType, Opcode};
use interpreter::Error;
use interpreter::module::{ModuleInstanceInterface, ItemIndex, CallerContext};
use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableType, VariableInstance};

const MEMORY_INDEX: u32 = 0;
const MEMORY_LIMIT_MIN: u32 = 1;

const STACKTOP_INDEX: u32 = 0;
const STACKTOP_DEFAULT: i32 = 0;
const TABLE_BASE_INDEX: u32 = 0;
const TABLE_BASE_DEFAULT: i32 = 0;

const INVOKE_VI_INDEX: u32 = 0;		// (i32, i32) -> ()
const INVOKE_INDEX: u32 = 1;		// (i32) -> ()

const TABLE_SIZE: u32 = 1024;
const TABLE_INDEX: u32 = 0;

pub struct EnvModuleInstance {
	module: Module,
	memory: Arc<MemoryInstance>,
	stacktop: Arc<VariableInstance>,
	table: Arc<TableInstance>,
}

impl EnvModuleInstance {
	pub fn new(module: Module) -> Result<Self, Error> {
		Ok(EnvModuleInstance {
			module: module,
			memory: MemoryInstance::new(&MemoryType::new(MEMORY_LIMIT_MIN, None))?,
			stacktop: Arc::new(VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(STACKTOP_DEFAULT))?),
			table: TableInstance::new(VariableType::AnyFunc, &TableType::new(TABLE_SIZE, None))?,
		})
	}
}

impl ModuleInstanceInterface for EnvModuleInstance {
	fn execute_main(&self, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn execute_index(&self, _index: u32, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn execute_export(&self, _name: &str, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn module(&self) -> &Module {
		&self.module
	}

	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
		match &index {
			&ItemIndex::Internal(TABLE_INDEX) => Ok(self.table.clone()),
			_ => Err(Error::Env(format!("trying to get table with index {:?} from env module", index))),
		}
	}

	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
		match &index {
			&ItemIndex::Internal(MEMORY_INDEX) => Ok(self.memory.clone()),
			_ => Err(Error::Env(format!("trying to get memory with index {:?} from env module", index))),
		}
	}

	fn global(&self, index: ItemIndex) -> Result<Arc<VariableInstance>, Error> {
		match &index {
			&ItemIndex::Internal(STACKTOP_INDEX) => Ok(self.stacktop.clone()),
			_ => Err(Error::Env(format!("trying to get global with index {:?} from env module", index))),
		}
	}

	fn call_function(&self, _outer: CallerContext, _index: ItemIndex) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn call_function_indirect(&self, _outer: CallerContext, _table_index: ItemIndex, _type_index: u32, _func_index: u32) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn call_internal_function(&self, _outer: CallerContext, _index: u32, _function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}
}

pub fn env_module() -> Result<EnvModuleInstance, Error> {
	let module = module()
		// memory regions
		.memory().with_min(MEMORY_LIMIT_MIN).build()
		.with_export(ExportEntry::new("memory".into(), Internal::Memory(MEMORY_INDEX)))
		// tables
		.table().with_min(TABLE_SIZE).build()
		.with_export(ExportEntry::new("table".into(), Internal::Table(TABLE_INDEX)))
		// globals
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(STACKTOP_DEFAULT)])))
		.with_export(ExportEntry::new("STACKTOP".into(), Internal::Global(STACKTOP_INDEX)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(TABLE_BASE_DEFAULT)])))
		.with_export(ExportEntry::new("tableBase".into(), Internal::Global(TABLE_BASE_INDEX)))
		// functions
		.with_export(ExportEntry::new("invoke_vi".into(), Internal::Function(INVOKE_VI_INDEX)))
		.with_export(ExportEntry::new("invoke".into(), Internal::Function(INVOKE_INDEX)))
		.build();

	EnvModuleInstance::new(module)
}
/*
  (import "env" "STACKTOP" (global (;0;) i32))
  (import "env" "invoke_vi" (func (;0;) (type 3)))
  (import "env" "invoke_v" (func (;1;) (type 1)))
  (import "env" "_storage_size" (func (;2;) (type 2)))
  (import "env" "_storage_write" (func (;3;) (type 4)))
  (import "env" "_abort" (func (;4;) (type 0)))
  (import "env" "_emscripten_memcpy_big" (func (;5;) (type 4)))
  (import "env" "___resumeException" (func (;6;) (type 1)))
  (import "env" "___cxa_find_matching_catch_2" (func (;7;) (type 2)))
  (import "env" "___gxx_personality_v0" (func (;8;) (type 6)))
  (import "env" "memory" (memory (;0;) 256 256))
  (import "env" "table" (table (;0;) 6 6 anyfunc))
  (import "env" "tableBase" (global (;1;) i32))
  (import "env" "gas" (func (;9;) (type 10)))
  (import "env" "_free" (func (;10;) (type 1)))
  (import "env" "_malloc" (func (;11;) (type 7)))
*/<commit_msg>continue env<commit_after>use std::sync::Arc;
use builder::module;
use elements::{Module, FunctionType, ExportEntry, Internal, MemoryType, GlobalEntry, GlobalType,
	ValueType, InitExpr, TableType, Opcode};
use interpreter::Error;
use interpreter::module::{ModuleInstanceInterface, ItemIndex, CallerContext};
use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableType, VariableInstance};

const MEMORY_INDEX: u32 = 0;
const MEMORY_LIMIT_MIN: u32 = 1;

const STACKTOP_INDEX: u32 = 0;
const STACKTOP_DEFAULT: i32 = 0;
const TABLE_BASE_INDEX: u32 = 0;
const TABLE_BASE_DEFAULT: i32 = 0;

const INVOKE_VI_INDEX: u32 = 0;		// (i32, i32) -> ()
const INVOKE_INDEX: u32 = 1;		// (i32) -> ()
const GAS_INDEX: u32 = 2;

const TABLE_SIZE: u32 = 1024;
const TABLE_INDEX: u32 = 0;

pub struct EnvModuleInstance {
	module: Module,
	memory: Arc<MemoryInstance>,
	stacktop: Arc<VariableInstance>,
	table: Arc<TableInstance>,
}

impl EnvModuleInstance {
	pub fn new(module: Module) -> Result<Self, Error> {
		Ok(EnvModuleInstance {
			module: module,
			memory: MemoryInstance::new(&MemoryType::new(MEMORY_LIMIT_MIN, None))?,
			stacktop: Arc::new(VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(STACKTOP_DEFAULT))?),
			table: TableInstance::new(VariableType::AnyFunc, &TableType::new(TABLE_SIZE, None))?,
		})
	}
}

impl ModuleInstanceInterface for EnvModuleInstance {
	fn execute_main(&self, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn execute_index(&self, _index: u32, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn execute_export(&self, _name: &str, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn module(&self) -> &Module {
		&self.module
	}

	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
		match &index {
			&ItemIndex::Internal(TABLE_INDEX) => Ok(self.table.clone()),
			_ => Err(Error::Env(format!("trying to get table with index {:?} from env module", index))),
		}
	}

	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
		match &index {
			&ItemIndex::Internal(MEMORY_INDEX) => Ok(self.memory.clone()),
			_ => Err(Error::Env(format!("trying to get memory with index {:?} from env module", index))),
		}
	}

	fn global(&self, index: ItemIndex) -> Result<Arc<VariableInstance>, Error> {
		match &index {
			&ItemIndex::Internal(STACKTOP_INDEX) => Ok(self.stacktop.clone()),
			_ => Err(Error::Env(format!("trying to get global with index {:?} from env module", index))),
		}
	}

	fn call_function(&self, _outer: CallerContext, _index: ItemIndex) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn call_function_indirect(&self, _outer: CallerContext, _table_index: ItemIndex, _type_index: u32, _func_index: u32) -> Result<Option<RuntimeValue>, Error> {
		unimplemented!()
	}

	fn call_internal_function(&self, _outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
		match index {
			GAS_INDEX => Ok(None),
			_ => unimplemented!(),
		}
	}
}

pub fn env_module() -> Result<EnvModuleInstance, Error> {
	let module = module()
		// memory regions
		.memory().with_min(MEMORY_LIMIT_MIN).build()
		.with_export(ExportEntry::new("memory".into(), Internal::Memory(MEMORY_INDEX)))
		// tables
		.table().with_min(TABLE_SIZE).build()
		.with_export(ExportEntry::new("table".into(), Internal::Table(TABLE_INDEX)))
		// globals
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(STACKTOP_DEFAULT)])))
		.with_export(ExportEntry::new("STACKTOP".into(), Internal::Global(STACKTOP_INDEX)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(TABLE_BASE_DEFAULT)])))
		.with_export(ExportEntry::new("tableBase".into(), Internal::Global(TABLE_BASE_INDEX)))
		// functions
		.with_export(ExportEntry::new("invoke_vi".into(), Internal::Function(INVOKE_VI_INDEX)))
		.with_export(ExportEntry::new("invoke".into(), Internal::Function(INVOKE_INDEX)))
		.with_export(ExportEntry::new("gas".into(), Internal::Function(GAS_INDEX)))
		.build();

	EnvModuleInstance::new(module)
}
/*
  (import "env" "STACKTOP" (global (;0;) i32))
  (import "env" "invoke_vi" (func (;0;) (type 3)))
  (import "env" "invoke_v" (func (;1;) (type 1)))
  (import "env" "_storage_size" (func (;2;) (type 2)))
  (import "env" "_storage_write" (func (;3;) (type 4)))
  (import "env" "_abort" (func (;4;) (type 0)))
  (import "env" "_emscripten_memcpy_big" (func (;5;) (type 4)))
  (import "env" "___resumeException" (func (;6;) (type 1)))
  (import "env" "___cxa_find_matching_catch_2" (func (;7;) (type 2)))
  (import "env" "___gxx_personality_v0" (func (;8;) (type 6)))
  (import "env" "memory" (memory (;0;) 256 256))
  (import "env" "table" (table (;0;) 6 6 anyfunc))
  (import "env" "tableBase" (global (;1;) i32))
  (import "env" "gas" (func (;9;) (type 10)))
  (import "env" "_free" (func (;10;) (type 1)))
  (import "env" "_malloc" (func (;11;) (type 7)))
*/<|endoftext|>


<commit_before>//! WebAssembly interpreter module.

use std::any::TypeId;
use std::error;
use std::fmt;
use validation;
use common;

/// Custom user error.
pub trait UserError: 'static + ::std::fmt::Display + ::std::fmt::Debug {
	#[doc(hidden)]
	fn __private_get_type_id__(&self) -> TypeId {
		TypeId::of::<Self>()
	}
}

impl UserError {
	/// Attempt to downcast this `UserError` to a concrete type by reference.
	pub fn downcast_ref<T: UserError>(&self) -> Option<&T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&*(self as *const UserError as *const T)) }
		} else {
			None
		}
	}

	/// Attempt to downcast this `UserError` to a concrete type by mutable
	/// reference.
	pub fn downcast_mut<T: UserError>(&mut self) -> Option<&mut T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&mut *(self as *mut UserError as *mut T)) }
		} else {
			None
		}
	}
}

/// Internal interpreter error.
#[derive(Debug)]
pub enum Error {
	/// Program-level error.
	Program(String),
	/// Validation error.
	Validation(String),
	/// Initialization error.
	Initialization(String),
	/// Function-level error.
	Function(String),
	/// Table-level error.
	Table(String),
	/// Memory-level error.
	Memory(String),
	/// Variable-level error.
	Variable(String),
	/// Global-level error.
	Global(String),
	/// Local-level error.
	Local(String),
	/// Stack-level error.
	Stack(String),
	/// Value-level error.
	Value(String),
	/// Interpreter (code) error.
	Interpreter(String),
	/// Native module error.
	Native(String),
	/// Trap.
	Trap(String),
	/// Custom user error.
	User(Box<UserError>),
}

impl Into<String> for Error {
	fn into(self) -> String {
		match self {
			Error::Program(s) => s,
			Error::Validation(s) => s,
			Error::Initialization(s) => s,
			Error::Function(s) => s,
			Error::Table(s) => s,
			Error::Memory(s) => s,
			Error::Variable(s) => s,
			Error::Global(s) => s,
			Error::Local(s) => s,
			Error::Stack(s) => s,
			Error::Interpreter(s) => s,
			Error::Value(s) => s,
			Error::Native(s) => s,
			Error::Trap(s) => format!("trap: {}", s),
			Error::User(e) => format!("user: {}", e),
		}
	}
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::Program(ref s) => write!(f, "Program: {}", s),
			Error::Validation(ref s) => write!(f, "Validation: {}", s),
			Error::Initialization(ref s) => write!(f, "Initialization: {}", s),
			Error::Function(ref s) => write!(f, "Function: {}", s),
			Error::Table(ref s) => write!(f, "Table: {}", s),
			Error::Memory(ref s) => write!(f, "Memory: {}", s),
			Error::Variable(ref s) => write!(f, "Variable: {}", s),
			Error::Global(ref s) => write!(f, "Global: {}", s),
			Error::Local(ref s) => write!(f, "Local: {}", s),
			Error::Stack(ref s) => write!(f, "Stack: {}", s),
			Error::Interpreter(ref s) => write!(f, "Interpreter: {}", s),
			Error::Value(ref s) => write!(f, "Value: {}", s),
			Error::Native(ref s) => write!(f, "Native: {}", s),
			Error::Trap(ref s) => write!(f, "Trap: {}", s),
			Error::User(ref e) => write!(f, "User: {}", e),
		}
	}
}

impl error::Error for Error {
	fn description(&self) -> &str {
		match *self {
			Error::Program(ref s) => s,
			Error::Validation(ref s) => s,
			Error::Initialization(ref s) => s,
			Error::Function(ref s) => s,
			Error::Table(ref s) => s,
			Error::Memory(ref s) => s,
			Error::Variable(ref s) => s,
			Error::Global(ref s) => s,
			Error::Local(ref s) => s,
			Error::Stack(ref s) => s,
			Error::Interpreter(ref s) => s,
			Error::Value(ref s) => s,
			Error::Native(ref s) => s,
			Error::Trap(ref s) => s,
			Error::User(_) => "User error",
		}
	}
}

impl<U> From<U> for Error where U: UserError + Sized {
	fn from(e: U) -> Self {
		Error::User(Box::new(e))
	}
}

impl From<validation::Error> for Error {
	fn from(e: validation::Error) -> Self {
		Error::Validation(e.to_string())
	}
}

impl From<common::stack::Error> for Error {
	fn from(e: common::stack::Error) -> Self {
		Error::Stack(e.to_string())
	}
}

mod validator;
mod native;
mod imports;
mod memory;
mod module;
mod program;
mod runner;
mod stack;
mod table;
mod value;
mod variable;

#[cfg(test)]
mod tests;

pub use self::memory::MemoryInstance;
pub use self::module::{ModuleInstance, ModuleInstanceInterface,
	ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
pub use self::table::TableInstance;
pub use self::program::ProgramInstance;
pub use self::value::RuntimeValue;
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
pub use self::native::{native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
<commit_msg>add deprecated warning<commit_after>//! WebAssembly interpreter module.

#![deprecated(since = "0.23", note = "Use wasmi crate to interpret wasm")]

use std::any::TypeId;
use std::error;
use std::fmt;
use validation;
use common;

/// Custom user error.
pub trait UserError: 'static + ::std::fmt::Display + ::std::fmt::Debug {
	#[doc(hidden)]
	fn __private_get_type_id__(&self) -> TypeId {
		TypeId::of::<Self>()
	}
}

impl UserError {
	/// Attempt to downcast this `UserError` to a concrete type by reference.
	pub fn downcast_ref<T: UserError>(&self) -> Option<&T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&*(self as *const UserError as *const T)) }
		} else {
			None
		}
	}

	/// Attempt to downcast this `UserError` to a concrete type by mutable
	/// reference.
	pub fn downcast_mut<T: UserError>(&mut self) -> Option<&mut T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&mut *(self as *mut UserError as *mut T)) }
		} else {
			None
		}
	}
}

/// Internal interpreter error.
#[derive(Debug)]
pub enum Error {
	/// Program-level error.
	Program(String),
	/// Validation error.
	Validation(String),
	/// Initialization error.
	Initialization(String),
	/// Function-level error.
	Function(String),
	/// Table-level error.
	Table(String),
	/// Memory-level error.
	Memory(String),
	/// Variable-level error.
	Variable(String),
	/// Global-level error.
	Global(String),
	/// Local-level error.
	Local(String),
	/// Stack-level error.
	Stack(String),
	/// Value-level error.
	Value(String),
	/// Interpreter (code) error.
	Interpreter(String),
	/// Native module error.
	Native(String),
	/// Trap.
	Trap(String),
	/// Custom user error.
	User(Box<UserError>),
}

impl Into<String> for Error {
	fn into(self) -> String {
		match self {
			Error::Program(s) => s,
			Error::Validation(s) => s,
			Error::Initialization(s) => s,
			Error::Function(s) => s,
			Error::Table(s) => s,
			Error::Memory(s) => s,
			Error::Variable(s) => s,
			Error::Global(s) => s,
			Error::Local(s) => s,
			Error::Stack(s) => s,
			Error::Interpreter(s) => s,
			Error::Value(s) => s,
			Error::Native(s) => s,
			Error::Trap(s) => format!("trap: {}", s),
			Error::User(e) => format!("user: {}", e),
		}
	}
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::Program(ref s) => write!(f, "Program: {}", s),
			Error::Validation(ref s) => write!(f, "Validation: {}", s),
			Error::Initialization(ref s) => write!(f, "Initialization: {}", s),
			Error::Function(ref s) => write!(f, "Function: {}", s),
			Error::Table(ref s) => write!(f, "Table: {}", s),
			Error::Memory(ref s) => write!(f, "Memory: {}", s),
			Error::Variable(ref s) => write!(f, "Variable: {}", s),
			Error::Global(ref s) => write!(f, "Global: {}", s),
			Error::Local(ref s) => write!(f, "Local: {}", s),
			Error::Stack(ref s) => write!(f, "Stack: {}", s),
			Error::Interpreter(ref s) => write!(f, "Interpreter: {}", s),
			Error::Value(ref s) => write!(f, "Value: {}", s),
			Error::Native(ref s) => write!(f, "Native: {}", s),
			Error::Trap(ref s) => write!(f, "Trap: {}", s),
			Error::User(ref e) => write!(f, "User: {}", e),
		}
	}
}

impl error::Error for Error {
	fn description(&self) -> &str {
		match *self {
			Error::Program(ref s) => s,
			Error::Validation(ref s) => s,
			Error::Initialization(ref s) => s,
			Error::Function(ref s) => s,
			Error::Table(ref s) => s,
			Error::Memory(ref s) => s,
			Error::Variable(ref s) => s,
			Error::Global(ref s) => s,
			Error::Local(ref s) => s,
			Error::Stack(ref s) => s,
			Error::Interpreter(ref s) => s,
			Error::Value(ref s) => s,
			Error::Native(ref s) => s,
			Error::Trap(ref s) => s,
			Error::User(_) => "User error",
		}
	}
}

impl<U> From<U> for Error where U: UserError + Sized {
	fn from(e: U) -> Self {
		Error::User(Box::new(e))
	}
}

impl From<validation::Error> for Error {
	fn from(e: validation::Error) -> Self {
		Error::Validation(e.to_string())
	}
}

impl From<common::stack::Error> for Error {
	fn from(e: common::stack::Error) -> Self {
		Error::Stack(e.to_string())
	}
}

mod validator;
mod native;
mod imports;
mod memory;
mod module;
mod program;
mod runner;
mod stack;
mod table;
mod value;
mod variable;

#[cfg(test)]
mod tests;

pub use self::memory::MemoryInstance;
pub use self::module::{ModuleInstance, ModuleInstanceInterface,
	ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
pub use self::table::TableInstance;
pub use self::program::ProgramInstance;
pub use self::value::RuntimeValue;
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
pub use self::native::{native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
<|endoftext|>