<commit_before>use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
use { gfx, Texture };
use gfx::format::{DepthStencil, Rgba8};
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;

const POS_COMPONENTS: usize = 2;
const UV_COMPONENTS: usize = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

gfx_vertex_struct!( PositionFormat {
    pos: [f32; 2] = "pos",
});

gfx_vertex_struct!( ColorFormat {
    color: [f32; 4] = "color",
});

gfx_vertex_struct!( TexCoordsFormat {
    uv: [f32; 2] = "uv",
});

gfx_pipeline!( pipe_colored {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
});

gfx_pipeline!( pipe_textured {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    uv: gfx::VertexBuffer<TexCoordsFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    texture: gfx::TextureSampler<[f32; 4]> = "s_texture",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
});

/// The data used for drawing 2D graphics.
pub struct Gfx2d<R: gfx::Resources> {
    buffer_pos: gfx::handle::Buffer<R, PositionFormat>,
    buffer_uv: gfx::handle::Buffer<R, TexCoordsFormat>,
    pso_colored: gfx::pso::PipelineState<R, pipe_colored::Meta>,
    pso_textured: gfx::pso::PipelineState<R, pipe_textured::Meta>,
    sampler: gfx::handle::Sampler<R>,
}

impl<R: gfx::Resources> Gfx2d<R> {
    /// Creates a new Gfx2d object.
    pub fn new<F>(opengl: OpenGL, factory: &mut F) -> Self
        where F: gfx::Factory<R>
    {
        use gfx::traits::*;
        use shaders::{ colored, textured };

        let glsl = opengl.to_glsl();

        let pso_colored = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, colored::VERTEX_GLSL_120)
                .set(GLSL::V1_50, colored::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, colored::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, colored::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_colored::new()
        ).unwrap();

        let pso_textured = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, textured::VERTEX_GLSL_120)
                .set(GLSL::V1_50, textured::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, textured::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, textured::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_textured::new()
        ).unwrap();

        let buffer_pos = factory.create_buffer_dynamic(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );
        let buffer_uv = factory.create_buffer_dynamic(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );

        let sampler_info = gfx::tex::SamplerInfo::new(
            gfx::tex::FilterMethod::Bilinear,
            gfx::tex::WrapMode::Clamp
        );
        let sampler = factory.create_sampler(sampler_info);

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            pso_colored: pso_colored,
            pso_textured: pso_textured,
            sampler: sampler
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C, F>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        output_color: &gfx::handle::RenderTargetView<R, Rgba8>,
        output_stencil: &gfx::handle::DepthStencilView<R, DepthStencil>,
        viewport: Viewport,
        f: F
    )
        where C: gfx::CommandBuffer<R>,
              F: FnOnce(Context, &mut GfxGraphics<R, C>)
    {
        let ref mut g = GfxGraphics::new(
            encoder,
            output_color,
            output_stencil,
            self
        );
        let c = Context::new_viewport(viewport);
        f(c, g);
    }
}

/// Used for rendering 2D graphics.
pub struct GfxGraphics<'a, R, C>
    where R: gfx::Resources + 'a,
          C: gfx::CommandBuffer<R> + 'a,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    encoder: &'a mut gfx::Encoder<R, C>,
    output_color: &'a gfx::handle::RenderTargetView<R, Rgba8>,
    output_stencil: &'a gfx::handle::DepthStencilView<R, DepthStencil>,
    g2d: &'a mut Gfx2d<R>,
}

impl<'a, R, C> GfxGraphics<'a, R, C>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
{
    /// Creates a new object for rendering 2D graphics.
    pub fn new(encoder: &'a mut gfx::Encoder<R, C>,
               output_color: &'a gfx::handle::RenderTargetView<R, Rgba8>,
               output_stencil: &'a gfx::handle::DepthStencilView<R, DepthStencil>,
               g2d: &'a mut Gfx2d<R>) -> Self {
        GfxGraphics {
            encoder: encoder,
            output_color: output_color,
            output_stencil: output_stencil,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture<R>) -> bool {
        use gfx::format::SurfaceType::*;

        match texture.surface.get_info().format {
            R4_G4_B4_A4
            | R5_G5_B5_A1
            | R8_G8_B8_A8
            | R10_G10_B10_A2
            | R16_G16_B16_A16
            | R32_G32_B32_A32 => true,
            R3_G3_B2
            | R4_G4
            | R5_G6_B5
            | R8 | R8_G8 | R8_G8_B8
            | R11_G11_B10
            | R16 | R16_G16 | R16_G16_B16
            | R32 | R32_G32 | R32_G32_B32
            | D16 | D24 | D24_S8 | D32 => false,
        }
    }
}

impl<'a, R, C> Graphics for GfxGraphics<'a, R, C>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    type Texture = Texture<R>;

    fn clear_color(&mut self, color: [f32; 4]) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            ..
        } = self;
        encoder.clear(output_color, color);
    }

    fn clear_stencil(&mut self, value: u8) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_stencil,
            ..
        } = self;
        encoder.clear_stencil(output_stencil, value);
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut pso_colored,
                ..
            },
            ..
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32]| {
            use std::mem::transmute;

            unsafe {
                encoder.update_buffer(&buffer_pos, transmute(vertices), 0)
                    .unwrap();
            }

            let data = pipe_colored::Data {
                pos: buffer_pos.clone(),
                color: *color,
                out_color: output_color.clone(),
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_colored, &data);
        })
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &<Self as Graphics>::Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut pso_textured,
                ref sampler,
                ..
            },
            ..
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            use std::mem::transmute;

            assert_eq!(
                vertices.len() * UV_COMPONENTS,
                texture_coords.len() * POS_COMPONENTS
            );
            unsafe {
                encoder.update_buffer(&buffer_pos, transmute(vertices), 0)
                    .unwrap();
                encoder.update_buffer(&buffer_uv, transmute(texture_coords), 0)
                    .unwrap();
            }

            let data = pipe_textured::Data {
                pos: buffer_pos.clone(),
                uv: buffer_uv.clone(),
                color: *color,
                texture: (texture.view.clone(), sampler.clone()),
                out_color: output_color.clone(),
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_textured, &data);
        })
    }
}
<commit_msg>Add blend_target and blend_ref to textured pipeline<commit_after>use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
use { gfx, Texture };
use gfx::format::{DepthStencil, Rgba8};
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;

const POS_COMPONENTS: usize = 2;
const UV_COMPONENTS: usize = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

gfx_vertex_struct!( PositionFormat {
    pos: [f32; 2] = "pos",
});

gfx_vertex_struct!( ColorFormat {
    color: [f32; 4] = "color",
});

gfx_vertex_struct!( TexCoordsFormat {
    uv: [f32; 2] = "uv",
});

gfx_pipeline!( pipe_colored {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
});

gfx_pipeline!( pipe_textured {
    pos: gfx::VertexBuffer<PositionFormat> = (),
    uv: gfx::VertexBuffer<TexCoordsFormat> = (),
    color: gfx::Global<[f32; 4]> = "color",
    texture: gfx::TextureSampler<[f32; 4]> = "s_texture",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "o_Color",
    blend_target: gfx::BlendTarget<gfx::format::Rgba8> =
        ("o_Color", gfx::state::MASK_ALL, gfx::preset::blend::ALPHA),
    blend_ref: gfx::BlendRef = (),
});

/// The data used for drawing 2D graphics.
pub struct Gfx2d<R: gfx::Resources> {
    buffer_pos: gfx::handle::Buffer<R, PositionFormat>,
    buffer_uv: gfx::handle::Buffer<R, TexCoordsFormat>,
    pso_colored: gfx::pso::PipelineState<R, pipe_colored::Meta>,
    pso_textured: gfx::pso::PipelineState<R, pipe_textured::Meta>,
    sampler: gfx::handle::Sampler<R>,
}

impl<R: gfx::Resources> Gfx2d<R> {
    /// Creates a new Gfx2d object.
    pub fn new<F>(opengl: OpenGL, factory: &mut F) -> Self
        where F: gfx::Factory<R>
    {
        use gfx::traits::*;
        use shaders::{ colored, textured };

        let glsl = opengl.to_glsl();

        let pso_colored = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, colored::VERTEX_GLSL_120)
                .set(GLSL::V1_50, colored::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, colored::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, colored::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_colored::new()
        ).unwrap();

        let pso_textured = factory.create_pipeline_simple(
            Shaders::new()
                .set(GLSL::V1_20, textured::VERTEX_GLSL_120)
                .set(GLSL::V1_50, textured::VERTEX_GLSL_150_CORE)
                .get(glsl).unwrap(),
            Shaders::new()
                .set(GLSL::V1_20, textured::FRAGMENT_GLSL_120)
                .set(GLSL::V1_50, textured::FRAGMENT_GLSL_150_CORE)
                .get(glsl).unwrap(),
            gfx::state::CullFace::Nothing,
            pipe_textured::new()
        ).unwrap();

        let buffer_pos = factory.create_buffer_dynamic(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );
        let buffer_uv = factory.create_buffer_dynamic(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::BufferRole::Vertex
        );

        let sampler_info = gfx::tex::SamplerInfo::new(
            gfx::tex::FilterMethod::Bilinear,
            gfx::tex::WrapMode::Clamp
        );
        let sampler = factory.create_sampler(sampler_info);

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            pso_colored: pso_colored,
            pso_textured: pso_textured,
            sampler: sampler
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C, F>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        output_color: &gfx::handle::RenderTargetView<R, Rgba8>,
        output_stencil: &gfx::handle::DepthStencilView<R, DepthStencil>,
        viewport: Viewport,
        f: F
    )
        where C: gfx::CommandBuffer<R>,
              F: FnOnce(Context, &mut GfxGraphics<R, C>)
    {
        let ref mut g = GfxGraphics::new(
            encoder,
            output_color,
            output_stencil,
            self
        );
        let c = Context::new_viewport(viewport);
        f(c, g);
    }
}

/// Used for rendering 2D graphics.
pub struct GfxGraphics<'a, R, C>
    where R: gfx::Resources + 'a,
          C: gfx::CommandBuffer<R> + 'a,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    encoder: &'a mut gfx::Encoder<R, C>,
    output_color: &'a gfx::handle::RenderTargetView<R, Rgba8>,
    output_stencil: &'a gfx::handle::DepthStencilView<R, DepthStencil>,
    g2d: &'a mut Gfx2d<R>,
}

impl<'a, R, C> GfxGraphics<'a, R, C>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
{
    /// Creates a new object for rendering 2D graphics.
    pub fn new(encoder: &'a mut gfx::Encoder<R, C>,
               output_color: &'a gfx::handle::RenderTargetView<R, Rgba8>,
               output_stencil: &'a gfx::handle::DepthStencilView<R, DepthStencil>,
               g2d: &'a mut Gfx2d<R>) -> Self {
        GfxGraphics {
            encoder: encoder,
            output_color: output_color,
            output_stencil: output_stencil,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture<R>) -> bool {
        use gfx::format::SurfaceType::*;

        match texture.surface.get_info().format {
            R4_G4_B4_A4
            | R5_G5_B5_A1
            | R8_G8_B8_A8
            | R10_G10_B10_A2
            | R16_G16_B16_A16
            | R32_G32_B32_A32 => true,
            R3_G3_B2
            | R4_G4
            | R5_G6_B5
            | R8 | R8_G8 | R8_G8_B8
            | R11_G11_B10
            | R16 | R16_G16 | R16_G16_B16
            | R32 | R32_G32 | R32_G32_B32
            | D16 | D24 | D24_S8 | D32 => false,
        }
    }
}

impl<'a, R, C> Graphics for GfxGraphics<'a, R, C>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>,
          R::Buffer: 'a,
          R::Shader: 'a,
          R::Program: 'a,
          R::Texture: 'a,
          R::Sampler: 'a
{
    type Texture = Texture<R>;

    fn clear_color(&mut self, color: [f32; 4]) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            ..
        } = self;
        encoder.clear(output_color, color);
    }

    fn clear_stencil(&mut self, value: u8) {
        let &mut GfxGraphics {
            ref mut encoder,
            output_stencil,
            ..
        } = self;
        encoder.clear_stencil(output_stencil, value);
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut pso_colored,
                ..
            },
            ..
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32]| {
            use std::mem::transmute;

            unsafe {
                encoder.update_buffer(&buffer_pos, transmute(vertices), 0)
                    .unwrap();
            }

            let data = pipe_colored::Data {
                pos: buffer_pos.clone(),
                color: *color,
                out_color: output_color.clone(),
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_colored, &data);
        })
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &<Self as Graphics>::Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let &mut GfxGraphics {
            ref mut encoder,
            output_color,
            g2d: &mut Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut pso_textured,
                ref sampler,
                ..
            },
            ..
        } = self;

        // TODO: Update draw state.

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            use std::mem::transmute;

            assert_eq!(
                vertices.len() * UV_COMPONENTS,
                texture_coords.len() * POS_COMPONENTS
            );
            unsafe {
                encoder.update_buffer(&buffer_pos, transmute(vertices), 0)
                    .unwrap();
                encoder.update_buffer(&buffer_uv, transmute(texture_coords), 0)
                    .unwrap();
            }

            let data = pipe_textured::Data {
                pos: buffer_pos.clone(),
                uv: buffer_uv.clone(),
                color: *color,
                texture: (texture.view.clone(), sampler.clone()),
                out_color: output_color.clone(),
                blend_target: output_color.clone(),
                blend_ref: [1.0; 4],
            };

            let n = vertices.len() / POS_COMPONENTS;
            let slice = gfx::Slice {
                    instances: None,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
            };
            encoder.draw(&slice, pso_textured, &data);
        })
    }
}
<|endoftext|>


<commit_before>use bits;
use consts;

#[derive(Copy, Clone)]
pub struct Decoder {
    pos: usize,
    decider: Decider,
}

impl Decoder {
    pub fn new(decider: Decider) -> Decoder {
        Decoder {
            // Decoder is created after first sample of first symbol after sync has
            // already been read.
            pos: 1,
            decider: decider,
        }
    }

    pub fn feed(&mut self, s: f32) -> Option<bits::Dibit> {
        self.pos += 1;
        self.pos %= consts::PERIOD;

        if self.pos == 0 {
            Some(self.decider.decide(s))
        } else {
            None
        }
    }
}

#[derive(Copy, Clone)]
pub struct Decider {
    pthresh: f32,
    mthresh: f32,
    nthresh: f32,
}

impl Decider {
    pub fn new(pthresh: f32, mthresh: f32, nthresh: f32) -> Decider {
        Decider {
            pthresh: pthresh,
            mthresh: mthresh,
            nthresh: nthresh,
        }
    }

    pub fn decide(&self, sample: f32) -> bits::Dibit {
        if sample >= self.pthresh {
            bits::Dibit::new(0b01)
        } else if sample >= self.mthresh && sample < self.pthresh {
            bits::Dibit::new(0b00)
        } else if sample < self.mthresh && sample >= self.nthresh {
            bits::Dibit::new(0b10)
        } else {
            bits::Dibit::new(0b11)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decider() {
        let d = Decider::new(-0.004, -0.1, -0.196);

        assert_eq!(d.decide(0.044).bits(), 0b01);
        assert_eq!(d.decide(-0.052).bits(), 0b00);
        assert_eq!(d.decide(-0.148).bits(), 0b10);
        assert_eq!(d.decide(-0.244).bits(), 0b11);
    }

    #[test]
    fn test_decoder() {
        let mut d = Decoder::new(Decider::new(0.0, 0.0, 0.0));

        assert!(d.feed(0.2099609375000000).is_none());
        assert!(d.feed(0.2165222167968750).is_none());
        assert!(d.feed(0.2179870605468750).is_none());
        assert!(d.feed(0.2152709960937500).is_none());
        assert!(d.feed(0.2094726562500000).is_none());
        assert!(d.feed(0.2018737792968750).is_none());
        assert!(d.feed(0.1937255859375000).is_none());
        assert!(d.feed(0.1861572265625000).is_none());
        assert!(d.feed(0.1799926757812500).is_some());

        assert!(d.feed(0.1752929687500000).is_none());
        assert!(d.feed(0.1726684570312500).is_none());
        assert!(d.feed(0.1720886230468750).is_none());
        assert!(d.feed(0.1732177734375000).is_none());
        assert!(d.feed(0.1754455566406250).is_none());
        assert!(d.feed(0.1780395507812500).is_none());
        assert!(d.feed(0.1803588867187500).is_none());
        assert!(d.feed(0.1817321777343750).is_none());
        assert!(d.feed(0.1816711425781250).is_none());
        assert!(d.feed(0.1799926757812500).is_some());
    }
}
<commit_msg>Fix up bounds to match theory<commit_after>use bits;
use consts;

#[derive(Copy, Clone)]
pub struct Decoder {
    pos: usize,
    decider: Decider,
}

impl Decoder {
    pub fn new(decider: Decider) -> Decoder {
        Decoder {
            // Decoder is created after first sample of first symbol after sync has
            // already been read.
            pos: 1,
            decider: decider,
        }
    }

    pub fn feed(&mut self, s: f32) -> Option<bits::Dibit> {
        self.pos += 1;
        self.pos %= consts::PERIOD;

        if self.pos == 0 {
            Some(self.decider.decide(s))
        } else {
            None
        }
    }
}

#[derive(Copy, Clone)]
pub struct Decider {
    pthresh: f32,
    mthresh: f32,
    nthresh: f32,
}

impl Decider {
    pub fn new(pthresh: f32, mthresh: f32, nthresh: f32) -> Decider {
        Decider {
            pthresh: pthresh,
            mthresh: mthresh,
            nthresh: nthresh,
        }
    }

    pub fn decide(&self, sample: f32) -> bits::Dibit {
        if sample > self.pthresh {
            bits::Dibit::new(0b01)
        } else if sample > self.mthresh && sample <= self.pthresh {
            bits::Dibit::new(0b00)
        } else if sample <= self.mthresh && sample > self.nthresh {
            bits::Dibit::new(0b10)
        } else {
            bits::Dibit::new(0b11)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decider() {
        let d = Decider::new(-0.004, -0.1, -0.196);

        assert_eq!(d.decide(0.044).bits(), 0b01);
        assert_eq!(d.decide(-0.052).bits(), 0b00);
        assert_eq!(d.decide(-0.148).bits(), 0b10);
        assert_eq!(d.decide(-0.244).bits(), 0b11);
    }

    #[test]
    fn test_decoder() {
        let mut d = Decoder::new(Decider::new(0.0, 0.0, 0.0));

        assert!(d.feed(0.2099609375000000).is_none());
        assert!(d.feed(0.2165222167968750).is_none());
        assert!(d.feed(0.2179870605468750).is_none());
        assert!(d.feed(0.2152709960937500).is_none());
        assert!(d.feed(0.2094726562500000).is_none());
        assert!(d.feed(0.2018737792968750).is_none());
        assert!(d.feed(0.1937255859375000).is_none());
        assert!(d.feed(0.1861572265625000).is_none());
        assert!(d.feed(0.1799926757812500).is_some());

        assert!(d.feed(0.1752929687500000).is_none());
        assert!(d.feed(0.1726684570312500).is_none());
        assert!(d.feed(0.1720886230468750).is_none());
        assert!(d.feed(0.1732177734375000).is_none());
        assert!(d.feed(0.1754455566406250).is_none());
        assert!(d.feed(0.1780395507812500).is_none());
        assert!(d.feed(0.1803588867187500).is_none());
        assert!(d.feed(0.1817321777343750).is_none());
        assert!(d.feed(0.1816711425781250).is_none());
        assert!(d.feed(0.1799926757812500).is_some());
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate clap;
extern crate config;
extern crate diesel;
#[macro_use]
extern crate failure;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate ring;
extern crate rocket;
extern crate rocket_contrib;
extern crate serde;
extern crate yaml_rust;

extern crate _aardwolf as aardwolf;

mod common;
use common::{configure, db_conn_string};

use failure::Error;
use ring::rand::SystemRandom;
use rocket::Rocket;
use rocket_contrib::Template;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use clap::App;

type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;

fn db_pool(rocket: &Rocket) -> Result<Pool, Error> {
    let database_url = rocket.config().get_str("database_url")?;
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    Ok(r2d2::Pool::builder().build(manager)?)
}

fn app(config: config::Config) -> Result<Rocket, Error> {
    let db_url = db_conn_string(&config)?;

    let c = rocket::Config::build(rocket::config::Environment::Development)
        .address(config.get_str("Web.Listen.address")?)
        .port(config.get::<u16>("Web.Listen.port")?)
        .extra("database_url", db_url.as_str())
        .unwrap();

    let mut routes = Vec::new();

    routes.extend(routes![
        aardwolf::routes::auth::sign_up_form,
        aardwolf::routes::auth::sign_up_form_with_error,
        aardwolf::routes::auth::sign_in_form,
        aardwolf::routes::auth::sign_in_form_with_error,
        aardwolf::routes::auth::sign_up,
        aardwolf::routes::auth::sign_in,
        aardwolf::routes::auth::confirm,
        aardwolf::routes::auth::sign_out,
        aardwolf::routes::app::home,
        aardwolf::routes::app::home_redirect,
    ]);

    #[cfg(debug_assertions)]
    routes.extend(routes![
        // assets
        aardwolf::routes::app::assets,
    ]);

    let r = rocket::custom(c, true)
        .mount(
            "/api/v1",
            routes![aardwolf::routes::applications::register_application],
        )
        .mount("/", routes)
        .attach(Template::fairing())
        .manage(SystemRandom::new());

    // we need an instance of the app to access the config values in Rocket.toml,
    // so we pass it to the db_pool function, get the pool, and _then_ return the instance
    let pool = db_pool(&r);
    Ok(r.manage(pool))
}

fn cli<'a, 'b>(yaml: &'a yaml_rust::yaml::Yaml) -> App<'a, 'b> {
    App::from_yaml(yaml)
        .name(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
}

fn main() {
    let yaml = load_yaml!("cli.yml");
    let cli = cli(&yaml);
    let config = configure(cli).unwrap();

    app(config).unwrap().launch();
}
<commit_msg>Add question mark to unwrap pool<commit_after>#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate clap;
extern crate config;
extern crate diesel;
#[macro_use]
extern crate failure;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate ring;
extern crate rocket;
extern crate rocket_contrib;
extern crate serde;
extern crate yaml_rust;

extern crate _aardwolf as aardwolf;

mod common;
use common::{configure, db_conn_string};

use failure::Error;
use ring::rand::SystemRandom;
use rocket::Rocket;
use rocket_contrib::Template;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use clap::App;

type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;

fn db_pool(rocket: &Rocket) -> Result<Pool, Error> {
    let database_url = rocket.config().get_str("database_url")?;
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    Ok(r2d2::Pool::builder().build(manager)?)
}

fn app(config: config::Config) -> Result<Rocket, Error> {
    let db_url = db_conn_string(&config)?;

    let c = rocket::Config::build(rocket::config::Environment::Development)
        .address(config.get_str("Web.Listen.address")?)
        .port(config.get::<u16>("Web.Listen.port")?)
        .extra("database_url", db_url.as_str())
        .unwrap();

    let mut routes = Vec::new();

    routes.extend(routes![
        aardwolf::routes::auth::sign_up_form,
        aardwolf::routes::auth::sign_up_form_with_error,
        aardwolf::routes::auth::sign_in_form,
        aardwolf::routes::auth::sign_in_form_with_error,
        aardwolf::routes::auth::sign_up,
        aardwolf::routes::auth::sign_in,
        aardwolf::routes::auth::confirm,
        aardwolf::routes::auth::sign_out,
        aardwolf::routes::app::home,
        aardwolf::routes::app::home_redirect,
    ]);

    #[cfg(debug_assertions)]
    routes.extend(routes![
        // assets
        aardwolf::routes::app::assets,
    ]);

    let r = rocket::custom(c, true)
        .mount(
            "/api/v1",
            routes![aardwolf::routes::applications::register_application],
        )
        .mount("/", routes)
        .attach(Template::fairing())
        .manage(SystemRandom::new());

    // we need an instance of the app to access the config values in Rocket.toml,
    // so we pass it to the db_pool function, get the pool, and _then_ return the instance
    let pool = db_pool(&r)?;
    Ok(r.manage(pool))
}

fn cli<'a, 'b>(yaml: &'a yaml_rust::yaml::Yaml) -> App<'a, 'b> {
    App::from_yaml(yaml)
        .name(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
}

fn main() {
    let yaml = load_yaml!("cli.yml");
    let cli = cli(&yaml);
    let config = configure(cli).unwrap();

    app(config).unwrap().launch();
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;

struct Function {
    blocks: HashMap<Block, BlockData>,
    instructions: HashMap<Inst, InstData>,
    uses: HashMap<Inst, UseList>,
    entry_block: Option<Block>,
    exit_block: Option<Block>,
}

impl Function {
    fn new() -> Function {
        Function {
            blocks: HashMap::new(),
            instructions: HashMap::new(),
            uses: HashMap::new(),
            entry_block: None,
            exit_block: None,
        }
    }
}

#[derive(PartialEq, Eq, Hash)]
struct Inst(u32);

#[derive(PartialEq, Eq, Hash)]
struct Block(u32);

struct UseList(Vec<Inst>);

struct BlockData {
    predecessors: Vec<Block>,
    successors: Vec<Block>,
    first_inst: Option<Inst>,
    last_inst: Option<Inst>,
}

impl BlockData {
    fn new() -> BlockData {
        BlockData {
            predecessors: Vec::new(),
            successors: Vec::new(),
            first_inst: None,
            last_inst: None,
        }
    }
}

enum CmpOp {
    Lt, Le, Eq, Ne, Gt, Ge,
}

enum InstData {
    Add {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Sub {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Goto {
        target: Block,
    },

    If {
        opnd: Inst,
        then_block: Block,
        else_block: Block,
    },

    Cmp {
        ty: Type,
        op: CmpOp,
        lhs: Inst,
        rhs: Inst,
    },

    Ret {
        opnd: Option<Inst>,
    },

    TrueConst,
    FalseConst,
    NilConst,
    Int8Const(u8),
    Int32Const(i32),
    Int64Const(i64),
    Float32Const(f32),
    Float64Const(f64),

    Param {
        ty: Type,
        idx: u32,
    },

    Deleted,
}

struct InstLoc {
    block: Option<Block>,
    prev: Option<Inst>,
    next: Option<Inst>,
}

enum Type {
    Bool,
    Int8,
    Int32,
    Int64,
    Float32,
    Float64,
    Reference,
}

#[cfg(test)]
mod tests {
    use super::Function;

    #[test]
    fn simple_fn() {
        let _fct = Function::new();
    }
}<commit_msg>boots: added UserList<commit_after>use std::collections::hash_map::HashMap;

struct Function {
    blocks: HashMap<Block, BlockData>,
    instructions: HashMap<Inst, InstData>,
    uses: HashMap<Inst, UseList>,
    users: HashMap<Inst, UserList>,
    entry_block: Option<Block>,
    exit_block: Option<Block>,
}

impl Function {
    fn new() -> Function {
        Function {
            blocks: HashMap::new(),
            instructions: HashMap::new(),
            uses: HashMap::new(),
            users: HashMap::new(),
            entry_block: None,
            exit_block: None,
        }
    }
}

#[derive(PartialEq, Eq, Hash)]
struct Inst(u32);

#[derive(PartialEq, Eq, Hash)]
struct Block(u32);

struct UseList(Vec<Inst>);
struct UserList(Vec<Inst>);

struct BlockData {
    predecessors: Vec<Block>,
    successors: Vec<Block>,
    first_inst: Option<Inst>,
    last_inst: Option<Inst>,
}

impl BlockData {
    fn new() -> BlockData {
        BlockData {
            predecessors: Vec::new(),
            successors: Vec::new(),
            first_inst: None,
            last_inst: None,
        }
    }
}

enum CmpOp {
    Lt, Le, Eq, Ne, Gt, Ge,
}

enum InstData {
    Add {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Sub {
        ty: Type,
        lhs: Inst,
        rhs: Inst,
    },

    Goto {
        target: Block,
    },

    If {
        opnd: Inst,
        then_block: Block,
        else_block: Block,
    },

    Cmp {
        ty: Type,
        op: CmpOp,
        lhs: Inst,
        rhs: Inst,
    },

    Ret {
        opnd: Option<Inst>,
    },

    TrueConst,
    FalseConst,
    NilConst,
    Int8Const(u8),
    Int32Const(i32),
    Int64Const(i64),
    Float32Const(f32),
    Float64Const(f64),

    Param {
        ty: Type,
        idx: u32,
    },

    Deleted,
}

struct InstLoc {
    block: Option<Block>,
    prev: Option<Inst>,
    next: Option<Inst>,
}

enum Type {
    Bool,
    Int8,
    Int32,
    Int64,
    Float32,
    Float64,
    Reference,
}

#[cfg(test)]
mod tests {
    use super::Function;

    #[test]
    fn simple_fn() {
        let _fct = Function::new();
    }
}<|endoftext|>


<commit_before>use client::PluginRegister;
use events::CommandEvent;

fn help(event: &CommandEvent) {
    {
        let plugins = event.client.plugins().read().unwrap();
        let commands = plugins.commands.keys().collect::<Vec<&String>>().connect(", ");

        event.client.reply_notice(event, format!("Available commands: {}", commands));
        if event.client.is_mask_admin(event.mask()) {
            let plugins = event.client.plugins().read().unwrap();
            let admin_commands = plugins.admin_commands.keys()
                .collect::<Vec<&String>>().connect(", ");
            event.client.reply_notice(event, format!("Admin commands: {}", admin_commands));
        }
    }
    {
        let state = event.client.state().read().unwrap();
        event.client.reply_notice(event,
            format!("Use a command with `{}command_name` or `{}, command_name`",
                event.client.command_prefix, state.nick));
    }
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("help", help);
}
<commit_msg>Workaround/fix for changes from https://github.com/rust-lang/rust/pull/25162<commit_after>use client::PluginRegister;
use events::CommandEvent;

fn help(event: &CommandEvent) {
    {
        let plugins = event.client.plugins().read().unwrap();
        // TODO: `.map(|s| &**s)` is a workaround for changes made in
        // https://github.com/rust-lang/rust/pull/25162 - it should be removed when (if) it
        // becomes no longer required
        let commands = plugins.commands.keys().map(|s| &**s).collect::<Vec<_>>().connect(", ");

        event.client.reply_notice(event, format!("Available commands: {}", commands));
        if event.client.is_mask_admin(event.mask()) {
            let plugins = event.client.plugins().read().unwrap();
            // TODO: `.map(|s| &**s)` is a workaround for changes made in
            // https://github.com/rust-lang/rust/pull/25162 - it should be removed when (if) it
            // becomes no longer required
            let admin_commands = plugins.admin_commands.keys().map(|s| &**s)
                .collect::<Vec<_>>().connect(", ");

            event.client.reply_notice(event, format!("Admin commands: {}", admin_commands));
        }
    }
    {
        let state = event.client.state().read().unwrap();
        event.client.reply_notice(event,
            format!("Use a command with `{}command_name` or `{}, command_name`",
                event.client.command_prefix, state.nick));
    }
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("help", help);
}
<|endoftext|>


<commit_before>// Generic AArch64 target for bare-metal code - Floating point disabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        abi: "softfloat".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "-mmx,-sse,+soft-float".to_string(),
        executables: true,
        disable_redzone: true,
        panic_strategy: PanicStrategy::Abort,
        code_model: Some(CodeModel::Kernel),
        ..Default::default()
    };
    Target {
        llvm_target: "x86_64-unknown-none-elf".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
            .to_string(),
        arch: "x86_64".to_string(),
        options: opts,
    }
}
<commit_msg>x86_64-unknown-none: Fix module comment<commit_after>// Generic x86-64 target for bare-metal code - Floating point disabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.

use super::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        abi: "softfloat".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "-mmx,-sse,+soft-float".to_string(),
        executables: true,
        disable_redzone: true,
        panic_strategy: PanicStrategy::Abort,
        code_model: Some(CodeModel::Kernel),
        ..Default::default()
    };
    Target {
        llvm_target: "x86_64-unknown-none-elf".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
            .to_string(),
        arch: "x86_64".to_string(),
        options: opts,
    }
}
<|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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Pointing", inherited=True, gecko_name="UserInterface") %>

<%helpers:longhand name="cursor" boxed="${product == 'gecko'}" animation_value_type="none"
  spec="https://drafts.csswg.org/css-ui/#cursor">
    pub use self::computed_value::T as SpecifiedValue;
    use values::computed::ComputedValueAsSpecified;
    #[cfg(feature = "gecko")]
    use values::specified::url::SpecifiedUrl;

    impl ComputedValueAsSpecified for SpecifiedValue {}
    no_viewport_percentage!(SpecifiedValue);

    pub mod computed_value {
        use std::fmt;
        use style_traits::cursor::Cursor;
        use style_traits::ToCss;
        #[cfg(feature = "gecko")]
        use values::specified::url::SpecifiedUrl;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum Keyword {
            AutoCursor,
            SpecifiedCursor(Cursor),
        }

        #[cfg(not(feature = "gecko"))]
        pub type T = Keyword;

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct Image {
            pub url: SpecifiedUrl,
            pub hotspot: Option<(f32, f32)>,
        }

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct T {
            pub images: Vec<Image>,
            pub keyword: Keyword,
        }

        impl ToCss for Keyword {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    Keyword::AutoCursor => dest.write_str("auto"),
                    Keyword::SpecifiedCursor(c) => c.to_css(dest),
                }
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for Image {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                try!(self.url.to_css(dest));
                if let Some((x, y)) = self.hotspot {
                    try!(dest.write_str(" "));
                    try!(x.to_css(dest));
                    try!(dest.write_str(" "));
                    try!(y.to_css(dest));
                }
                Ok(())
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                for url in &self.images {
                    try!(url.to_css(dest));
                    try!(dest.write_str(", "));
                }
                self.keyword.to_css(dest)
            }
        }
    }

    #[cfg(not(feature = "gecko"))]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::Keyword::AutoCursor
    }

    #[cfg(feature = "gecko")]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T {
            images: vec![],
            keyword: computed_value::Keyword::AutoCursor
        }
    }

    impl Parse for computed_value::Keyword {
        fn parse(_context: &ParserContext, input: &mut Parser) -> Result<computed_value::Keyword, ()> {
            use std::ascii::AsciiExt;
            use style_traits::cursor::Cursor;
            let ident = try!(input.expect_ident());
            if ident.eq_ignore_ascii_case("auto") {
                Ok(computed_value::Keyword::AutoCursor)
            } else {
                Cursor::from_css_keyword(&ident).map(computed_value::Keyword::SpecifiedCursor)
            }
        }
    }

    #[cfg(feature = "gecko")]
    fn parse_image(context: &ParserContext, input: &mut Parser) -> Result<computed_value::Image, ()> {
        Ok(computed_value::Image {
            url: try!(SpecifiedUrl::parse(context, input)),
            hotspot: match input.try(|input| input.expect_number()) {
                Ok(number) => Some((number, try!(input.expect_number()))),
                Err(()) => None,
            },
        })
    }

    #[cfg(not(feature = "gecko"))]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        computed_value::Keyword::parse(context, input)
    }

    /// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
    #[cfg(feature = "gecko")]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        let mut images = vec![];
        loop {
            match input.try(|input| parse_image(context, input)) {
                Ok(mut image) => {
                    image.url.build_image_value();
                    images.push(image)
                }
                Err(()) => break,
            }
            try!(input.expect_comma());
        }

        Ok(computed_value::T {
            images: images,
            keyword: try!(computed_value::Keyword::parse(context, input)),
        })
    }
</%helpers:longhand>

// NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
// is nonstandard, slated for CSS4-UI.
// TODO(pcwalton): SVG-only values.
${helpers.single_keyword("pointer-events", "auto none", animation_value_type="discrete",
                         extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
                         spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty")}

${helpers.single_keyword("-moz-user-input", "auto none enabled disabled",
                         products="gecko", gecko_ffi_name="mUserInput",
                         gecko_enum_prefix="StyleUserInput",
                         gecko_inexhaustive=True,
                         animation_value_type="discrete",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)")}

${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only",
                         products="gecko", gecko_ffi_name="mUserModify",
                         gecko_enum_prefix="StyleUserModify",
                         needs_conversion=True,
                         animation_value_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)")}

${helpers.single_keyword("-moz-user-focus",
                         "none ignore normal select-after select-before select-menu select-same select-all",
                         products="gecko", gecko_ffi_name="mUserFocus",
                         gecko_enum_prefix="StyleUserFocus",
                         gecko_inexhaustive=True,
                         animation_value_type="discrete",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)")}

${helpers.predefined_type("caret-color",
                          "ColorOrAuto",
                          "Either::Second(Auto)",
                          spec="https://drafts.csswg.org/css-ui/#caret-color",
                          animation_value_type="Either<IntermediateColor, Auto>",
                          boxed=True,
                          products="gecko")}
<commit_msg>Implements pointing related discrete animatable properties<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Pointing", inherited=True, gecko_name="UserInterface") %>

<%helpers:longhand name="cursor" boxed="${product == 'gecko'}" animation_value_type="none"
  spec="https://drafts.csswg.org/css-ui/#cursor">
    pub use self::computed_value::T as SpecifiedValue;
    use values::computed::ComputedValueAsSpecified;
    #[cfg(feature = "gecko")]
    use values::specified::url::SpecifiedUrl;

    impl ComputedValueAsSpecified for SpecifiedValue {}
    no_viewport_percentage!(SpecifiedValue);

    pub mod computed_value {
        use std::fmt;
        use style_traits::cursor::Cursor;
        use style_traits::ToCss;
        #[cfg(feature = "gecko")]
        use values::specified::url::SpecifiedUrl;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum Keyword {
            AutoCursor,
            SpecifiedCursor(Cursor),
        }

        #[cfg(not(feature = "gecko"))]
        pub type T = Keyword;

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct Image {
            pub url: SpecifiedUrl,
            pub hotspot: Option<(f32, f32)>,
        }

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct T {
            pub images: Vec<Image>,
            pub keyword: Keyword,
        }

        impl ToCss for Keyword {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    Keyword::AutoCursor => dest.write_str("auto"),
                    Keyword::SpecifiedCursor(c) => c.to_css(dest),
                }
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for Image {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                try!(self.url.to_css(dest));
                if let Some((x, y)) = self.hotspot {
                    try!(dest.write_str(" "));
                    try!(x.to_css(dest));
                    try!(dest.write_str(" "));
                    try!(y.to_css(dest));
                }
                Ok(())
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                for url in &self.images {
                    try!(url.to_css(dest));
                    try!(dest.write_str(", "));
                }
                self.keyword.to_css(dest)
            }
        }
    }

    #[cfg(not(feature = "gecko"))]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::Keyword::AutoCursor
    }

    #[cfg(feature = "gecko")]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T {
            images: vec![],
            keyword: computed_value::Keyword::AutoCursor
        }
    }

    impl Parse for computed_value::Keyword {
        fn parse(_context: &ParserContext, input: &mut Parser) -> Result<computed_value::Keyword, ()> {
            use std::ascii::AsciiExt;
            use style_traits::cursor::Cursor;
            let ident = try!(input.expect_ident());
            if ident.eq_ignore_ascii_case("auto") {
                Ok(computed_value::Keyword::AutoCursor)
            } else {
                Cursor::from_css_keyword(&ident).map(computed_value::Keyword::SpecifiedCursor)
            }
        }
    }

    #[cfg(feature = "gecko")]
    fn parse_image(context: &ParserContext, input: &mut Parser) -> Result<computed_value::Image, ()> {
        Ok(computed_value::Image {
            url: try!(SpecifiedUrl::parse(context, input)),
            hotspot: match input.try(|input| input.expect_number()) {
                Ok(number) => Some((number, try!(input.expect_number()))),
                Err(()) => None,
            },
        })
    }

    #[cfg(not(feature = "gecko"))]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        computed_value::Keyword::parse(context, input)
    }

    /// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
    #[cfg(feature = "gecko")]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        let mut images = vec![];
        loop {
            match input.try(|input| parse_image(context, input)) {
                Ok(mut image) => {
                    image.url.build_image_value();
                    images.push(image)
                }
                Err(()) => break,
            }
            try!(input.expect_comma());
        }

        Ok(computed_value::T {
            images: images,
            keyword: try!(computed_value::Keyword::parse(context, input)),
        })
    }
</%helpers:longhand>

// NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
// is nonstandard, slated for CSS4-UI.
// TODO(pcwalton): SVG-only values.
${helpers.single_keyword("pointer-events", "auto none", animation_value_type="discrete",
                         extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
                         spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty")}

${helpers.single_keyword("-moz-user-input", "auto none enabled disabled",
                         products="gecko", gecko_ffi_name="mUserInput",
                         gecko_enum_prefix="StyleUserInput",
                         gecko_inexhaustive=True,
                         animation_value_type="discrete",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)")}

${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only",
                         products="gecko", gecko_ffi_name="mUserModify",
                         gecko_enum_prefix="StyleUserModify",
                         needs_conversion=True,
                         gecko_inexhaustive=True,
                         animation_value_type="discrete",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)")}

${helpers.single_keyword("-moz-user-focus",
                         "none ignore normal select-after select-before select-menu select-same select-all",
                         products="gecko", gecko_ffi_name="mUserFocus",
                         gecko_enum_prefix="StyleUserFocus",
                         gecko_inexhaustive=True,
                         animation_value_type="discrete",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)")}

${helpers.predefined_type("caret-color",
                          "ColorOrAuto",
                          "Either::Second(Auto)",
                          spec="https://drafts.csswg.org/css-ui/#caret-color",
                          animation_value_type="Either<IntermediateColor, Auto>",
                          boxed=True,
                          products="gecko")}
<|endoftext|>


<commit_before>use crate::{Enum, EnumMap};
use core::iter::{Enumerate, FusedIterator};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ptr;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(value, match key {
///             Example::A => 3,
///             _ => 0,
///         });
///     }
/// }
/// ```
#[derive(Debug)]
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Enum<V>, V> Clone for Iter<'a, K, V> {
    fn clone(&self) -> Self {
        Iter {
            _phantom: PhantomData,
            iterator: self.iterator.clone(),
        }
    }
}

impl<'a, K: Enum<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
#[derive(Debug)]
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Enum<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}

/// A map iterator that moves out of map.
///
/// This struct is created by `into_iter` on `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
/// }
///
/// fn main() {
///     let map = enum_map! { Example::A | Example::B => String::from("123") };
///     for (_, value) in map {
///         assert_eq!(value + "4", "1234");
///     }
/// }
/// ```
pub struct IntoIter<K: Enum<V>, V> {
    map: ManuallyDrop<EnumMap<K, V>>,
    position: usize,
}

impl<K: Enum<V>, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<(K, V)> {
        let slice = self.map.as_slice();
        if self.position < slice.len() {
            let key = K::from_usize(self.position);
            let result = Some((key, unsafe { ptr::read(&slice[self.position]) }));
            self.position += 1;
            result
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let slice = self.map.as_slice();
        let diff = slice.len() - self.position;
        (diff, Some(diff))
    }
}

impl<K: Enum<V>, V> ExactSizeIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> FusedIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> Drop for IntoIter<K, V> {
    #[inline]
    fn drop(&mut self) {
        for _item in self {}
    }
}

impl<K: Enum<V>, V> IntoIterator for EnumMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            map: ManuallyDrop::new(self),
            position: 0,
        }
    }
}

impl<K: Enum<V>, V> EnumMap<K, V> {
    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let map = enum_map! { false => 3, true => 4 };
    ///     let mut values = map.values();
    ///     assert_eq!(values.next(), Some(&3));
    ///     assert_eq!(values.next(), Some(&4));
    ///     assert_eq!(values.next(), None);
    /// }
    /// ```
    #[inline]
    pub fn values(&self) -> Values<V> {
        Values(self.as_slice().iter())
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 2 };
    ///     for value in map.values_mut() {
    ///         *value += 2;
    ///     }
    ///     assert_eq!(map[false], 4);
    ///     assert_eq!(map[true], 4);
    /// }
    /// ```
    #[inline]
    pub fn values_mut(&mut self) -> ValuesMut<V> {
        ValuesMut(self.as_mut_slice().iter_mut())
    }
}

/// An iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values` method of `EnumMap`.
/// See its documentation for more.
pub struct Values<'a, V: 'a>(slice::Iter<'a, V>);

impl<'a, V: 'a> Iterator for Values<'a, V> {
    type Item = &'a V;
    #[inline]
    fn next(&mut self) -> Option<&'a V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for Values<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for Values<'a, V> {}

impl<'a, V: 'a> FusedIterator for Values<'a, V> {}

/// A mutable iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values_mut` method of `EnumMap`.
/// See its documentation for more.
pub struct ValuesMut<'a, V: 'a>(slice::IterMut<'a, V>);

impl<'a, V: 'a> Iterator for ValuesMut<'a, V> {
    type Item = &'a mut V;
    #[inline]
    fn next(&mut self) -> Option<&'a mut V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for ValuesMut<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a mut V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for ValuesMut<'a, V> {}

impl<'a, V: 'a> FusedIterator for ValuesMut<'a, V> {}
<commit_msg>Implement Clone for Values<commit_after>use crate::{Enum, EnumMap};
use core::iter::{Enumerate, FusedIterator};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ptr;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(value, match key {
///             Example::A => 3,
///             _ => 0,
///         });
///     }
/// }
/// ```
#[derive(Debug)]
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Enum<V>, V> Clone for Iter<'a, K, V> {
    fn clone(&self) -> Self {
        Iter {
            _phantom: PhantomData,
            iterator: self.iterator.clone(),
        }
    }
}

impl<'a, K: Enum<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for Iter<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
#[derive(Debug)]
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Enum<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: Enum<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: Enum<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> FusedIterator for IterMut<'a, K, V> {}

impl<'a, K: Enum<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}

/// A map iterator that moves out of map.
///
/// This struct is created by `into_iter` on `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
/// }
///
/// fn main() {
///     let map = enum_map! { Example::A | Example::B => String::from("123") };
///     for (_, value) in map {
///         assert_eq!(value + "4", "1234");
///     }
/// }
/// ```
pub struct IntoIter<K: Enum<V>, V> {
    map: ManuallyDrop<EnumMap<K, V>>,
    position: usize,
}

impl<K: Enum<V>, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<(K, V)> {
        let slice = self.map.as_slice();
        if self.position < slice.len() {
            let key = K::from_usize(self.position);
            let result = Some((key, unsafe { ptr::read(&slice[self.position]) }));
            self.position += 1;
            result
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let slice = self.map.as_slice();
        let diff = slice.len() - self.position;
        (diff, Some(diff))
    }
}

impl<K: Enum<V>, V> ExactSizeIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> FusedIterator for IntoIter<K, V> {}

impl<K: Enum<V>, V> Drop for IntoIter<K, V> {
    #[inline]
    fn drop(&mut self) {
        for _item in self {}
    }
}

impl<K: Enum<V>, V> IntoIterator for EnumMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            map: ManuallyDrop::new(self),
            position: 0,
        }
    }
}

impl<K: Enum<V>, V> EnumMap<K, V> {
    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let map = enum_map! { false => 3, true => 4 };
    ///     let mut values = map.values();
    ///     assert_eq!(values.next(), Some(&3));
    ///     assert_eq!(values.next(), Some(&4));
    ///     assert_eq!(values.next(), None);
    /// }
    /// ```
    #[inline]
    pub fn values(&self) -> Values<V> {
        Values(self.as_slice().iter())
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// fn main() {
    ///     let mut map = enum_map! { _ => 2 };
    ///     for value in map.values_mut() {
    ///         *value += 2;
    ///     }
    ///     assert_eq!(map[false], 4);
    ///     assert_eq!(map[true], 4);
    /// }
    /// ```
    #[inline]
    pub fn values_mut(&mut self) -> ValuesMut<V> {
        ValuesMut(self.as_mut_slice().iter_mut())
    }
}

/// An iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values` method of `EnumMap`.
/// See its documentation for more.
pub struct Values<'a, V: 'a>(slice::Iter<'a, V>);

impl<'a, V> Clone for Values<'a, V> {
    fn clone(&self) -> Self {
        Values(self.0.clone())
    }
}

impl<'a, V: 'a> Iterator for Values<'a, V> {
    type Item = &'a V;
    #[inline]
    fn next(&mut self) -> Option<&'a V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for Values<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for Values<'a, V> {}

impl<'a, V: 'a> FusedIterator for Values<'a, V> {}

/// A mutable iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values_mut` method of `EnumMap`.
/// See its documentation for more.
pub struct ValuesMut<'a, V: 'a>(slice::IterMut<'a, V>);

impl<'a, V: 'a> Iterator for ValuesMut<'a, V> {
    type Item = &'a mut V;
    #[inline]
    fn next(&mut self) -> Option<&'a mut V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for ValuesMut<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a mut V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for ValuesMut<'a, V> {}

impl<'a, V: 'a> FusedIterator for ValuesMut<'a, V> {}
<|endoftext|>


<commit_before>s! {
    // FIXME this is actually a union
    #[cfg_attr(arget_pointer_width = "32",
               repr(align(4)))]
    #[cfg_attr(target_pointer_width = "64",
               repr(align(8)))]
    pub struct sem_t {
        #[cfg(target_pointer_width = "32")]
        __size: [::c_char; 16],
        #[cfg(target_pointer_width = "64")]
        __size: [::c_char; 32],
    }
}
<commit_msg>Auto merge of #1287 - red75prime:pr-uclibc-mips32-align, r=gnzlbg<commit_after>s! {
    // FIXME this is actually a union
    #[cfg_attr(target_pointer_width = "32",
               repr(align(4)))]
    #[cfg_attr(target_pointer_width = "64",
               repr(align(8)))]
    pub struct sem_t {
        #[cfg(target_pointer_width = "32")]
        __size: [::c_char; 16],
        #[cfg(target_pointer_width = "64")]
        __size: [::c_char; 32],
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

//! Native representation of JS Promise values.
//!
//! This implementation differs from the traditional Rust DOM object, because the reflector
//! is provided by SpiderMonkey and has no knowledge of an associated native representation
//! (ie. dom::Promise). This means that native instances use native reference counting (Rc)
//! to ensure that no memory is leaked, which means that there can be multiple instances of
//! native Promise values that refer to the same JS value yet are distinct native objects
//! (ie. address equality for the native objects is meaningless).

use crate::compartments::{AlreadyInCompartment, InCompartment};
use crate::dom::bindings::conversions::root_from_object;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
use crate::dom::bindings::utils::AsCCharPtrPtr;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promisenativehandler::PromiseNativeHandler;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::{AddRawValueRoot, CallArgs, GetFunctionNativeReserved};
use js::jsapi::{Heap, JS_ClearPendingException};
use js::jsapi::{JSAutoCompartment, JSContext, JSObject, JS_GetFunctionObject};
use js::jsapi::{JS_NewFunction, NewFunctionWithReserved, PromiseState};
use js::jsapi::{RemoveRawValueRoot, SetFunctionNativeReserved};
use js::jsval::{Int32Value, JSVal, ObjectValue, UndefinedValue};
use js::rust::wrappers::{
    AddPromiseReactions, CallOriginalPromiseReject, CallOriginalPromiseResolve,
};
use js::rust::wrappers::{GetPromiseState, IsPromiseObject};
use js::rust::wrappers::{NewPromiseObject, RejectPromise, ResolvePromise};
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
use std::ptr;
use std::rc::Rc;

#[dom_struct]
#[allow_unrooted_in_rc]
pub struct Promise {
    reflector: Reflector,
    /// Since Promise values are natively reference counted without the knowledge of
    /// the SpiderMonkey GC, an explicit root for the reflector is stored while any
    /// native instance exists. This ensures that the reflector will never be GCed
    /// while native code could still interact with its native representation.
    #[ignore_malloc_size_of = "SM handles JS values"]
    permanent_js_root: Heap<JSVal>,
}

/// Private helper to enable adding new methods to Rc<Promise>.
trait PromiseHelper {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext);
}

impl PromiseHelper for Rc<Promise> {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext) {
        let obj = self.reflector().get_jsobject();
        self.permanent_js_root.set(ObjectValue(*obj));
        assert!(AddRawValueRoot(
            cx,
            self.permanent_js_root.get_unsafe(),
            b"Promise::root\0".as_c_char_ptr()
        ));
    }
}

impl Drop for Promise {
    #[allow(unsafe_code)]
    fn drop(&mut self) {
        unsafe {
            let object = self.permanent_js_root.get().to_object();
            assert!(!object.is_null());
            let cx = Runtime::get();
            assert!(!cx.is_null());
            RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe());
        }
    }
}

impl Promise {
    pub fn new(global: &GlobalScope) -> Rc<Promise> {
        let comp = AlreadyInCompartment::assert(&global);
        Promise::new_in_current_compartment(global, InCompartment::Already(&comp))
    }

    #[allow(unsafe_code)]
    pub fn new_in_current_compartment(global: &GlobalScope, _comp: InCompartment) -> Rc<Promise> {
        let cx = global.get_cx();
        rooted!(in(cx) let mut obj = ptr::null_mut::<JSObject>());
        unsafe {
            Promise::create_js_promise(cx, HandleObject::null(), obj.handle_mut());
            Promise::new_with_js_promise(obj.handle(), cx)
        }
    }

    #[allow(unsafe_code)]
    pub fn duplicate(&self) -> Rc<Promise> {
        let cx = self.global().get_cx();
        unsafe { Promise::new_with_js_promise(self.reflector().get_jsobject(), cx) }
    }

    #[allow(unsafe_code, unrooted_must_root)]
    pub unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> {
        assert!(IsPromiseObject(obj));
        let promise = Promise {
            reflector: Reflector::new(),
            permanent_js_root: Heap::default(),
        };
        let mut promise = Rc::new(promise);
        Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get());
        promise.initialize(cx);
        promise
    }

    #[allow(unsafe_code)]
    unsafe fn create_js_promise(
        cx: *mut JSContext,
        proto: HandleObject,
        mut obj: MutableHandleObject,
    ) {
        let do_nothing_func = JS_NewFunction(
            cx,
            Some(do_nothing_promise_executor),
            /* nargs = */ 2,
            /* flags = */ 0,
            ptr::null(),
        );
        assert!(!do_nothing_func.is_null());
        rooted!(in(cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func));
        assert!(!do_nothing_obj.is_null());
        obj.set(NewPromiseObject(cx, do_nothing_obj.handle(), proto));
        assert!(!obj.is_null());
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_resolved(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseResolve(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_rejected(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseReject(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unsafe_code)]
    pub fn resolve_native<T>(&self, val: &T)
    where
        T: ToJSValConvertible,
    {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.resolve(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn resolve(&self, cx: *mut JSContext, value: HandleValue) {
        if !ResolvePromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_native<T>(&self, val: &T)
    where
        T: ToJSValConvertible,
    {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_error(&self, error: Error) {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            error.to_jsval(cx, &self.global(), v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn reject(&self, cx: *mut JSContext, value: HandleValue) {
        if !RejectPromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn is_fulfilled(&self) -> bool {
        let state = unsafe { GetPromiseState(self.promise_obj()) };
        match state {
            PromiseState::Rejected | PromiseState::Fulfilled => true,
            _ => false,
        }
    }

    #[allow(unsafe_code)]
    fn promise_obj(&self) -> HandleObject {
        let obj = self.reflector().get_jsobject();
        unsafe {
            assert!(IsPromiseObject(obj));
        }
        obj
    }

    #[allow(unsafe_code)]
    pub fn append_native_handler(&self, handler: &PromiseNativeHandler) {
        let cx = self.global().get_cx();
        rooted!(in(cx) let resolve_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Resolve));

        rooted!(in(cx) let reject_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Reject));

        unsafe {
            let ok = AddPromiseReactions(
                cx,
                self.promise_obj(),
                resolve_func.handle(),
                reject_func.handle(),
            );
            assert!(ok);
        }
    }
}

#[allow(unsafe_code)]
unsafe extern "C" fn do_nothing_promise_executor(
    _cx: *mut JSContext,
    argc: u32,
    vp: *mut JSVal,
) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    *args.rval() = UndefinedValue();
    true
}

const SLOT_NATIVEHANDLER: usize = 0;
const SLOT_NATIVEHANDLER_TASK: usize = 1;

#[derive(PartialEq)]
enum NativeHandlerTask {
    Resolve = 0,
    Reject = 1,
}

#[allow(unsafe_code)]
unsafe extern "C" fn native_handler_callback(
    cx: *mut JSContext,
    argc: u32,
    vp: *mut JSVal,
) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER));
    assert!(v.get().is_object());

    let handler = root_from_object::<PromiseNativeHandler>(v.to_object())
        .expect("unexpected value for native handler in promise native handler callback");

    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER_TASK));
    match v.to_int32() {
        v if v == NativeHandlerTask::Resolve as i32 => {
            handler.resolved_callback(cx, HandleValue::from_raw(args.get(0)))
        },
        v if v == NativeHandlerTask::Reject as i32 => {
            handler.rejected_callback(cx, HandleValue::from_raw(args.get(0)))
        },
        _ => panic!("unexpected native handler task value"),
    };

    true
}

#[allow(unsafe_code)]
fn create_native_handler_function(
    cx: *mut JSContext,
    holder: HandleObject,
    task: NativeHandlerTask,
) -> *mut JSObject {
    unsafe {
        let func = NewFunctionWithReserved(cx, Some(native_handler_callback), 1, 0, ptr::null());
        assert!(!func.is_null());

        rooted!(in(cx) let obj = JS_GetFunctionObject(func));
        assert!(!obj.is_null());
        SetFunctionNativeReserved(obj.get(), SLOT_NATIVEHANDLER, &ObjectValue(*holder));
        SetFunctionNativeReserved(obj.get(), SLOT_NATIVEHANDLER_TASK, &Int32Value(task as i32));
        obj.get()
    }
}
<commit_msg>Create new compartment in Promise constructor<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 https://mozilla.org/MPL/2.0/. */

//! Native representation of JS Promise values.
//!
//! This implementation differs from the traditional Rust DOM object, because the reflector
//! is provided by SpiderMonkey and has no knowledge of an associated native representation
//! (ie. dom::Promise). This means that native instances use native reference counting (Rc)
//! to ensure that no memory is leaked, which means that there can be multiple instances of
//! native Promise values that refer to the same JS value yet are distinct native objects
//! (ie. address equality for the native objects is meaningless).

use crate::compartments::InCompartment;
use crate::dom::bindings::conversions::root_from_object;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
use crate::dom::bindings::utils::AsCCharPtrPtr;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promisenativehandler::PromiseNativeHandler;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::{AddRawValueRoot, CallArgs, GetFunctionNativeReserved};
use js::jsapi::{Heap, JS_ClearPendingException};
use js::jsapi::{JSAutoCompartment, JSContext, JSObject, JS_GetFunctionObject};
use js::jsapi::{JS_NewFunction, NewFunctionWithReserved, PromiseState};
use js::jsapi::{RemoveRawValueRoot, SetFunctionNativeReserved};
use js::jsval::{Int32Value, JSVal, ObjectValue, UndefinedValue};
use js::rust::wrappers::{
    AddPromiseReactions, CallOriginalPromiseReject, CallOriginalPromiseResolve,
};
use js::rust::wrappers::{GetPromiseState, IsPromiseObject};
use js::rust::wrappers::{NewPromiseObject, RejectPromise, ResolvePromise};
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
use std::ptr;
use std::rc::Rc;

#[dom_struct]
#[allow_unrooted_in_rc]
pub struct Promise {
    reflector: Reflector,
    /// Since Promise values are natively reference counted without the knowledge of
    /// the SpiderMonkey GC, an explicit root for the reflector is stored while any
    /// native instance exists. This ensures that the reflector will never be GCed
    /// while native code could still interact with its native representation.
    #[ignore_malloc_size_of = "SM handles JS values"]
    permanent_js_root: Heap<JSVal>,
}

/// Private helper to enable adding new methods to Rc<Promise>.
trait PromiseHelper {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext);
}

impl PromiseHelper for Rc<Promise> {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext) {
        let obj = self.reflector().get_jsobject();
        self.permanent_js_root.set(ObjectValue(*obj));
        assert!(AddRawValueRoot(
            cx,
            self.permanent_js_root.get_unsafe(),
            b"Promise::root\0".as_c_char_ptr()
        ));
    }
}

impl Drop for Promise {
    #[allow(unsafe_code)]
    fn drop(&mut self) {
        unsafe {
            let object = self.permanent_js_root.get().to_object();
            assert!(!object.is_null());
            let cx = Runtime::get();
            assert!(!cx.is_null());
            RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe());
        }
    }
}

impl Promise {
    pub fn new(global: &GlobalScope) -> Rc<Promise> {
        let compartment =
            JSAutoCompartment::new(global.get_cx(), global.reflector().get_jsobject().get());
        let comp = InCompartment::Entered(&compartment);
        Promise::new_in_current_compartment(global, comp)
    }

    #[allow(unsafe_code)]
    pub fn new_in_current_compartment(global: &GlobalScope, _comp: InCompartment) -> Rc<Promise> {
        let cx = global.get_cx();
        rooted!(in(cx) let mut obj = ptr::null_mut::<JSObject>());
        unsafe {
            Promise::create_js_promise(cx, HandleObject::null(), obj.handle_mut());
            Promise::new_with_js_promise(obj.handle(), cx)
        }
    }

    #[allow(unsafe_code)]
    pub fn duplicate(&self) -> Rc<Promise> {
        let cx = self.global().get_cx();
        unsafe { Promise::new_with_js_promise(self.reflector().get_jsobject(), cx) }
    }

    #[allow(unsafe_code, unrooted_must_root)]
    pub unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> {
        assert!(IsPromiseObject(obj));
        let promise = Promise {
            reflector: Reflector::new(),
            permanent_js_root: Heap::default(),
        };
        let mut promise = Rc::new(promise);
        Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get());
        promise.initialize(cx);
        promise
    }

    #[allow(unsafe_code)]
    unsafe fn create_js_promise(
        cx: *mut JSContext,
        proto: HandleObject,
        mut obj: MutableHandleObject,
    ) {
        let do_nothing_func = JS_NewFunction(
            cx,
            Some(do_nothing_promise_executor),
            /* nargs = */ 2,
            /* flags = */ 0,
            ptr::null(),
        );
        assert!(!do_nothing_func.is_null());
        rooted!(in(cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func));
        assert!(!do_nothing_obj.is_null());
        obj.set(NewPromiseObject(cx, do_nothing_obj.handle(), proto));
        assert!(!obj.is_null());
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_resolved(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseResolve(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_rejected(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseReject(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unsafe_code)]
    pub fn resolve_native<T>(&self, val: &T)
    where
        T: ToJSValConvertible,
    {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.resolve(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn resolve(&self, cx: *mut JSContext, value: HandleValue) {
        if !ResolvePromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_native<T>(&self, val: &T)
    where
        T: ToJSValConvertible,
    {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_error(&self, error: Error) {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            error.to_jsval(cx, &self.global(), v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn reject(&self, cx: *mut JSContext, value: HandleValue) {
        if !RejectPromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn is_fulfilled(&self) -> bool {
        let state = unsafe { GetPromiseState(self.promise_obj()) };
        match state {
            PromiseState::Rejected | PromiseState::Fulfilled => true,
            _ => false,
        }
    }

    #[allow(unsafe_code)]
    fn promise_obj(&self) -> HandleObject {
        let obj = self.reflector().get_jsobject();
        unsafe {
            assert!(IsPromiseObject(obj));
        }
        obj
    }

    #[allow(unsafe_code)]
    pub fn append_native_handler(&self, handler: &PromiseNativeHandler) {
        let cx = self.global().get_cx();
        rooted!(in(cx) let resolve_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Resolve));

        rooted!(in(cx) let reject_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Reject));

        unsafe {
            let ok = AddPromiseReactions(
                cx,
                self.promise_obj(),
                resolve_func.handle(),
                reject_func.handle(),
            );
            assert!(ok);
        }
    }
}

#[allow(unsafe_code)]
unsafe extern "C" fn do_nothing_promise_executor(
    _cx: *mut JSContext,
    argc: u32,
    vp: *mut JSVal,
) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    *args.rval() = UndefinedValue();
    true
}

const SLOT_NATIVEHANDLER: usize = 0;
const SLOT_NATIVEHANDLER_TASK: usize = 1;

#[derive(PartialEq)]
enum NativeHandlerTask {
    Resolve = 0,
    Reject = 1,
}

#[allow(unsafe_code)]
unsafe extern "C" fn native_handler_callback(
    cx: *mut JSContext,
    argc: u32,
    vp: *mut JSVal,
) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER));
    assert!(v.get().is_object());

    let handler = root_from_object::<PromiseNativeHandler>(v.to_object())
        .expect("unexpected value for native handler in promise native handler callback");

    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER_TASK));
    match v.to_int32() {
        v if v == NativeHandlerTask::Resolve as i32 => {
            handler.resolved_callback(cx, HandleValue::from_raw(args.get(0)))
        },
        v if v == NativeHandlerTask::Reject as i32 => {
            handler.rejected_callback(cx, HandleValue::from_raw(args.get(0)))
        },
        _ => panic!("unexpected native handler task value"),
    };

    true
}

#[allow(unsafe_code)]
fn create_native_handler_function(
    cx: *mut JSContext,
    holder: HandleObject,
    task: NativeHandlerTask,
) -> *mut JSObject {
    unsafe {
        let func = NewFunctionWithReserved(cx, Some(native_handler_callback), 1, 0, ptr::null());
        assert!(!func.is_null());

        rooted!(in(cx) let obj = JS_GetFunctionObject(func));
        assert!(!obj.is_null());
        SetFunctionNativeReserved(obj.get(), SLOT_NATIVEHANDLER, &ObjectValue(*holder));
        SetFunctionNativeReserved(obj.get(), SLOT_NATIVEHANDLER_TASK, &Int32Value(task as i32));
        obj.get()
    }
}
<|endoftext|>