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

extern mod opengles;   // FIXME: Should only be for tests.
use glut::{swap_buffers, GLint};
use glut::{init, DOUBLE, init_display_mode, create_window, display_func, timer_func, check_loop, destroy_window};
use self::opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
use self::opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
use self::opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLenum};
use self::opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
use self::opengles::gl2::{buffer_data, create_program, clear, clear_color};
use self::opengles::gl2::{compile_shader, create_shader, draw_arrays};
use self::opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
use self::opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use self::opengles::gl2::{get_shader_info_log, get_shader_iv};
use self::opengles::gl2::{link_program, shader_source};
use self::opengles::gl2::{use_program, vertex_attrib_pointer_f32};

use std::comm;
use std::libc::c_int;
use std::io::println;
use std::task;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[source_str.as_bytes().to_owned()]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!(~"failed to compile shader with error");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail!(~"failed to compile shader");
    }
    return shader_id;
}

struct ShaderProgram {
    program: GLuint,
    aVertexPosition: c_int,
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/
}

fn ShaderProgram(program: GLuint) -> ShaderProgram {
    let p = ShaderProgram {
        program : program,
        aVertexPosition : get_attrib_location(program, ~"aVertexPosition"),
        /*self.uPMatrix : get_uniform_location(program, "uPMatrix"),
        self.uMVMatrix : get_uniform_location(program, "uMVMatrix")*/
    };
    enable_vertex_attrib_array(p.aVertexPosition as GLuint);
    return p;
}

fn init_shaders() -> ShaderProgram {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!(~"failed to initialize program");
    }

    use_program(program);

    return ShaderProgram(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: ShaderProgram, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

/*
#[test]
fn test_triangle_and_square() {
    let (po, ch): (Port<()>, Chan<()>) = stream();
    let _result_ch: Chan<()> = do spawn_listener | _po | {
        init();
        init_display_mode(DOUBLE);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let (wakeup, wakeup_chan): (Port<()>, Chan<()>) = stream();

        do timer_func(1000) { wakeup_chan.send(()); }

        loop {
            check_loop();

            if wakeup.peek() {
                wakeup.recv();
                ch.send(());
                destroy_window(window);
                break;
            }
        }
    };

    po.recv();
}
*/

pub fn spawn_listener<A: Owned>(f: ~fn(Port<A>)) -> Chan<A> {
    let (setup_po, setup_ch) = comm::stream();
    do task::spawn {
        let (po, ch) = comm::stream();
        setup_ch.send(ch);
        f(po);
    }
    setup_po.recv()
}
<commit_msg>Update tests for latest Rust.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod opengles;   // FIXME: Should only be for tests.
use glut::{swap_buffers, GLint};
use glut::{init, DOUBLE, init_display_mode, create_window, display_func, timer_func, check_loop, destroy_window};
use self::opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
use self::opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
use self::opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLenum};
use self::opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
use self::opengles::gl2::{buffer_data, create_program, clear, clear_color};
use self::opengles::gl2::{compile_shader, create_shader, draw_arrays};
use self::opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
use self::opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use self::opengles::gl2::{get_shader_info_log, get_shader_iv};
use self::opengles::gl2::{link_program, shader_source};
use self::opengles::gl2::{use_program, vertex_attrib_pointer_f32};

use std::comm;
use std::libc::c_int;
use std::io::println;
use std::task;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[source_str.as_bytes().to_owned()]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!(~"failed to compile shader with error");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail!(~"failed to compile shader");
    }
    return shader_id;
}

struct ShaderProgram {
    program: GLuint,
    aVertexPosition: c_int,
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/
}

fn ShaderProgram(program: GLuint) -> ShaderProgram {
    let p = ShaderProgram {
        program : program,
        aVertexPosition : get_attrib_location(program, ~"aVertexPosition"),
        /*self.uPMatrix : get_uniform_location(program, "uPMatrix"),
        self.uMVMatrix : get_uniform_location(program, "uMVMatrix")*/
    };
    enable_vertex_attrib_array(p.aVertexPosition as GLuint);
    return p;
}

fn init_shaders() -> ShaderProgram {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!(~"failed to initialize program");
    }

    use_program(program);

    return ShaderProgram(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: ShaderProgram, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

/*
#[test]
fn test_triangle_and_square() {
    let (po, ch): (Port<()>, Chan<()>) = stream();
    let _result_ch: Chan<()> = do spawn_listener | _po | {
        init();
        init_display_mode(DOUBLE);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let (wakeup, wakeup_chan): (Port<()>, Chan<()>) = stream();

        do timer_func(1000) { wakeup_chan.send(()); }

        loop {
            check_loop();

            if wakeup.peek() {
                wakeup.recv();
                ch.send(());
                destroy_window(window);
                break;
            }
        }
    };

    po.recv();
}
*/

pub fn spawn_listener<A: Send>(f: ~fn(Port<A>)) -> Chan<A> {
    let (setup_po, setup_ch) = comm::stream();
    do task::spawn {
        let (po, ch) = comm::stream();
        setup_ch.send(ch);
        f(po);
    }
    setup_po.recv()
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Provides an implementation of the audio_streams::shm_streams::ShmStream trait using the VioS
//! client.
//! Given that the VioS server doesn't emit an event when the next buffer is expected, this
//! implementation uses thread::sleep to drive the frame timings.

use super::shm_vios::{VioSClient, VioSStreamParams};

use crate::virtio::snd::constants::*;

use audio_streams::shm_streams::{BufferSet, ServerRequest, ShmStream, ShmStreamSource};
use audio_streams::{BoxError, SampleFormat, StreamDirection, StreamEffect};

use base::{error, SharedMemory, SharedMemoryUnix};

use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::Path;
use std::sync::Arc;
use std::time::{Duration, Instant};

use sys_util::{Error as SysError, SharedMemory as SysSharedMemory};

use super::shm_vios::{Error, Result};

// This is the error type used in audio_streams::shm_streams. Unfortunately, it's not declared
// public there so it needs to be re-declared here. It also prevents the usage of anyhow::Error.
type GenericResult<T> = std::result::Result<T, BoxError>;

/// Adapter that provides the ShmStreamSource trait around the VioS backend.
pub struct VioSShmStreamSource {
    vios_client: Arc<VioSClient>,
}

impl VioSShmStreamSource {
    /// Creates a new stream source given the path to the audio server's socket.
    pub fn new<P: AsRef<Path>>(server: P) -> Result<VioSShmStreamSource> {
        Ok(Self {
            vios_client: Arc::new(VioSClient::try_new(server)?),
        })
    }
}

fn from_sample_format(format: SampleFormat) -> u8 {
    match format {
        SampleFormat::U8 => VIRTIO_SND_PCM_FMT_U8,
        SampleFormat::S16LE => VIRTIO_SND_PCM_FMT_U16,
        SampleFormat::S24LE => VIRTIO_SND_PCM_FMT_U24,
        SampleFormat::S32LE => VIRTIO_SND_PCM_FMT_U32,
    }
}

fn virtio_frame_rate(frame_rate: u32) -> GenericResult<u8> {
    Ok(match frame_rate {
        5512u32 => VIRTIO_SND_PCM_RATE_5512,
        8000u32 => VIRTIO_SND_PCM_RATE_8000,
        11025u32 => VIRTIO_SND_PCM_RATE_11025,
        16000u32 => VIRTIO_SND_PCM_RATE_16000,
        22050u32 => VIRTIO_SND_PCM_RATE_22050,
        32000u32 => VIRTIO_SND_PCM_RATE_32000,
        44100u32 => VIRTIO_SND_PCM_RATE_44100,
        48000u32 => VIRTIO_SND_PCM_RATE_48000,
        64000u32 => VIRTIO_SND_PCM_RATE_64000,
        88200u32 => VIRTIO_SND_PCM_RATE_88200,
        96000u32 => VIRTIO_SND_PCM_RATE_96000,
        176400u32 => VIRTIO_SND_PCM_RATE_176400,
        192000u32 => VIRTIO_SND_PCM_RATE_192000,
        384000u32 => VIRTIO_SND_PCM_RATE_384000,
        _ => {
            return Err(Box::new(Error::UnsupportedFrameRate(frame_rate)));
        }
    })
}

impl VioSShmStreamSource {
    fn new_stream_inner(
        &mut self,
        stream_id: u32,
        direction: StreamDirection,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        buffer_size: usize,
        _effects: &[StreamEffect],
        client_shm: &SysSharedMemory,
        _buffer_offsets: [u64; 2],
    ) -> GenericResult<Box<dyn ShmStream>> {
        let frame_size = num_channels * format.sample_bytes();
        let period_bytes = (frame_size * buffer_size) as u32;
        self.vios_client.prepare_stream(stream_id)?;
        let params = VioSStreamParams {
            buffer_bytes: 2 * period_bytes,
            period_bytes,
            features: 0u32,
            channels: num_channels as u8,
            format: from_sample_format(format),
            rate: virtio_frame_rate(frame_rate)?,
        };
        self.vios_client.set_stream_parameters(stream_id, params)?;
        self.vios_client.start_stream(stream_id)?;
        VioSndShmStream::new(
            buffer_size,
            num_channels,
            format,
            frame_rate,
            stream_id,
            direction,
            self.vios_client.clone(),
            client_shm,
        )
    }
}

impl ShmStreamSource for VioSShmStreamSource {
    /// Creates a new stream
    #[allow(clippy::too_many_arguments)]
    fn new_stream(
        &mut self,
        direction: StreamDirection,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        buffer_size: usize,
        effects: &[StreamEffect],
        client_shm: &SysSharedMemory,
        buffer_offsets: [u64; 2],
    ) -> GenericResult<Box<dyn ShmStream>> {
        self.vios_client.ensure_bg_thread_started()?;
        let virtio_dir = match direction {
            StreamDirection::Playback => VIRTIO_SND_D_OUTPUT,
            StreamDirection::Capture => VIRTIO_SND_D_INPUT,
        };
        let stream_id = self
            .vios_client
            .get_unused_stream_id(virtio_dir)
            .ok_or(Box::new(Error::NoStreamsAvailable))?;
        self.new_stream_inner(
            stream_id,
            direction,
            num_channels,
            format,
            frame_rate,
            buffer_size,
            effects,
            client_shm,
            buffer_offsets,
        )
        .map_err(|e| {
            // Attempt to release the stream so that it can be used later. This is a best effort
            // attempt, so we ignore any error it may return.
            let _ = self.vios_client.release_stream(stream_id);
            e
        })
    }

    /// Get a list of file descriptors used by the implementation.
    ///
    /// Returns any open file descriptors needed by the implementation.
    /// This list helps users of the ShmStreamSource enter Linux jails without
    /// closing needed file descriptors.
    fn keep_fds(&self) -> Vec<RawFd> {
        self.vios_client.keep_fds()
    }
}

/// Adapter around a VioS stream that implements the ShmStream trait.
pub struct VioSndShmStream {
    num_channels: usize,
    frame_rate: u32,
    buffer_size: usize,
    frame_size: usize,
    interval: Duration,
    next_frame: Duration,
    start_time: Instant,
    stream_id: u32,
    direction: StreamDirection,
    vios_client: Arc<VioSClient>,
    client_shm: SharedMemory,
}

impl VioSndShmStream {
    /// Creates a new shm stream.
    fn new(
        buffer_size: usize,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        stream_id: u32,
        direction: StreamDirection,
        vios_client: Arc<VioSClient>,
        client_shm: &SysSharedMemory,
    ) -> GenericResult<Box<dyn ShmStream>> {
        let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);

        let dup_fd = unsafe {
            // Safe because fcntl doesn't affect memory and client_shm should wrap a known valid
            // file descriptor.
            libc::fcntl(client_shm.as_raw_fd(), libc::F_DUPFD_CLOEXEC, 0)
        };
        if dup_fd < 0 {
            return Err(Box::new(Error::DupError(SysError::last())));
        }
        let file = unsafe {
            // safe because we checked the result of libc::fcntl()
            File::from_raw_fd(dup_fd)
        };
        let client_shm_clone = SharedMemory::from_file(file).map_err(Error::BaseMmapError)?;

        Ok(Box::new(Self {
            num_channels,
            frame_rate,
            buffer_size,
            frame_size: format.sample_bytes() * num_channels,
            interval,
            next_frame: interval,
            start_time: Instant::now(),
            stream_id,
            direction,
            vios_client,
            client_shm: client_shm_clone,
        }))
    }
}

impl ShmStream for VioSndShmStream {
    fn frame_size(&self) -> usize {
        self.frame_size
    }

    fn num_channels(&self) -> usize {
        self.num_channels
    }

    fn frame_rate(&self) -> u32 {
        self.frame_rate
    }

    /// Waits until the next time a frame should be sent to the server. The server may release the
    /// previous buffer much sooner than it needs the next one, so this function may sleep to wait
    /// for the right time.
    fn wait_for_next_action_with_timeout(
        &mut self,
        timeout: Duration,
    ) -> GenericResult<Option<ServerRequest>> {
        let elapsed = self.start_time.elapsed();
        if elapsed < self.next_frame {
            if timeout < self.next_frame - elapsed {
                std::thread::sleep(timeout);
                return Ok(None);
            } else {
                std::thread::sleep(self.next_frame - elapsed);
            }
        }
        self.next_frame += self.interval;
        Ok(Some(ServerRequest::new(self.buffer_size, self)))
    }
}

impl BufferSet for VioSndShmStream {
    fn callback(&mut self, offset: usize, frames: usize) -> GenericResult<()> {
        match self.direction {
            StreamDirection::Playback => {
                self.vios_client.inject_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
            StreamDirection::Capture => {
                self.vios_client.request_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
        }
        Ok(())
    }

    fn ignore(&mut self) -> GenericResult<()> {
        Ok(())
    }
}

impl Drop for VioSndShmStream {
    fn drop(&mut self) {
        let stream_id = self.stream_id;
        if let Err(e) = self
            .vios_client
            .stop_stream(stream_id)
            .and_then(|_| self.vios_client.release_stream(stream_id))
        {
            error!("Failed to stop and release stream {}: {}", stream_id, e);
        }
    }
}
<commit_msg>devices: vios: Fix SampleFormat => VIRTIO_SND_PCM_FMT mapping<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Provides an implementation of the audio_streams::shm_streams::ShmStream trait using the VioS
//! client.
//! Given that the VioS server doesn't emit an event when the next buffer is expected, this
//! implementation uses thread::sleep to drive the frame timings.

use super::shm_vios::{VioSClient, VioSStreamParams};

use crate::virtio::snd::constants::*;

use audio_streams::shm_streams::{BufferSet, ServerRequest, ShmStream, ShmStreamSource};
use audio_streams::{BoxError, SampleFormat, StreamDirection, StreamEffect};

use base::{error, SharedMemory, SharedMemoryUnix};

use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::Path;
use std::sync::Arc;
use std::time::{Duration, Instant};

use sys_util::{Error as SysError, SharedMemory as SysSharedMemory};

use super::shm_vios::{Error, Result};

// This is the error type used in audio_streams::shm_streams. Unfortunately, it's not declared
// public there so it needs to be re-declared here. It also prevents the usage of anyhow::Error.
type GenericResult<T> = std::result::Result<T, BoxError>;

/// Adapter that provides the ShmStreamSource trait around the VioS backend.
pub struct VioSShmStreamSource {
    vios_client: Arc<VioSClient>,
}

impl VioSShmStreamSource {
    /// Creates a new stream source given the path to the audio server's socket.
    pub fn new<P: AsRef<Path>>(server: P) -> Result<VioSShmStreamSource> {
        Ok(Self {
            vios_client: Arc::new(VioSClient::try_new(server)?),
        })
    }
}

fn from_sample_format(format: SampleFormat) -> u8 {
    match format {
        SampleFormat::U8 => VIRTIO_SND_PCM_FMT_U8,
        SampleFormat::S16LE => VIRTIO_SND_PCM_FMT_S16,
        SampleFormat::S24LE => VIRTIO_SND_PCM_FMT_S24,
        SampleFormat::S32LE => VIRTIO_SND_PCM_FMT_S32,
    }
}

fn virtio_frame_rate(frame_rate: u32) -> GenericResult<u8> {
    Ok(match frame_rate {
        5512u32 => VIRTIO_SND_PCM_RATE_5512,
        8000u32 => VIRTIO_SND_PCM_RATE_8000,
        11025u32 => VIRTIO_SND_PCM_RATE_11025,
        16000u32 => VIRTIO_SND_PCM_RATE_16000,
        22050u32 => VIRTIO_SND_PCM_RATE_22050,
        32000u32 => VIRTIO_SND_PCM_RATE_32000,
        44100u32 => VIRTIO_SND_PCM_RATE_44100,
        48000u32 => VIRTIO_SND_PCM_RATE_48000,
        64000u32 => VIRTIO_SND_PCM_RATE_64000,
        88200u32 => VIRTIO_SND_PCM_RATE_88200,
        96000u32 => VIRTIO_SND_PCM_RATE_96000,
        176400u32 => VIRTIO_SND_PCM_RATE_176400,
        192000u32 => VIRTIO_SND_PCM_RATE_192000,
        384000u32 => VIRTIO_SND_PCM_RATE_384000,
        _ => {
            return Err(Box::new(Error::UnsupportedFrameRate(frame_rate)));
        }
    })
}

impl VioSShmStreamSource {
    fn new_stream_inner(
        &mut self,
        stream_id: u32,
        direction: StreamDirection,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        buffer_size: usize,
        _effects: &[StreamEffect],
        client_shm: &SysSharedMemory,
        _buffer_offsets: [u64; 2],
    ) -> GenericResult<Box<dyn ShmStream>> {
        let frame_size = num_channels * format.sample_bytes();
        let period_bytes = (frame_size * buffer_size) as u32;
        self.vios_client.prepare_stream(stream_id)?;
        let params = VioSStreamParams {
            buffer_bytes: 2 * period_bytes,
            period_bytes,
            features: 0u32,
            channels: num_channels as u8,
            format: from_sample_format(format),
            rate: virtio_frame_rate(frame_rate)?,
        };
        self.vios_client.set_stream_parameters(stream_id, params)?;
        self.vios_client.start_stream(stream_id)?;
        VioSndShmStream::new(
            buffer_size,
            num_channels,
            format,
            frame_rate,
            stream_id,
            direction,
            self.vios_client.clone(),
            client_shm,
        )
    }
}

impl ShmStreamSource for VioSShmStreamSource {
    /// Creates a new stream
    #[allow(clippy::too_many_arguments)]
    fn new_stream(
        &mut self,
        direction: StreamDirection,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        buffer_size: usize,
        effects: &[StreamEffect],
        client_shm: &SysSharedMemory,
        buffer_offsets: [u64; 2],
    ) -> GenericResult<Box<dyn ShmStream>> {
        self.vios_client.ensure_bg_thread_started()?;
        let virtio_dir = match direction {
            StreamDirection::Playback => VIRTIO_SND_D_OUTPUT,
            StreamDirection::Capture => VIRTIO_SND_D_INPUT,
        };
        let stream_id = self
            .vios_client
            .get_unused_stream_id(virtio_dir)
            .ok_or(Box::new(Error::NoStreamsAvailable))?;
        self.new_stream_inner(
            stream_id,
            direction,
            num_channels,
            format,
            frame_rate,
            buffer_size,
            effects,
            client_shm,
            buffer_offsets,
        )
        .map_err(|e| {
            // Attempt to release the stream so that it can be used later. This is a best effort
            // attempt, so we ignore any error it may return.
            let _ = self.vios_client.release_stream(stream_id);
            e
        })
    }

    /// Get a list of file descriptors used by the implementation.
    ///
    /// Returns any open file descriptors needed by the implementation.
    /// This list helps users of the ShmStreamSource enter Linux jails without
    /// closing needed file descriptors.
    fn keep_fds(&self) -> Vec<RawFd> {
        self.vios_client.keep_fds()
    }
}

/// Adapter around a VioS stream that implements the ShmStream trait.
pub struct VioSndShmStream {
    num_channels: usize,
    frame_rate: u32,
    buffer_size: usize,
    frame_size: usize,
    interval: Duration,
    next_frame: Duration,
    start_time: Instant,
    stream_id: u32,
    direction: StreamDirection,
    vios_client: Arc<VioSClient>,
    client_shm: SharedMemory,
}

impl VioSndShmStream {
    /// Creates a new shm stream.
    fn new(
        buffer_size: usize,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        stream_id: u32,
        direction: StreamDirection,
        vios_client: Arc<VioSClient>,
        client_shm: &SysSharedMemory,
    ) -> GenericResult<Box<dyn ShmStream>> {
        let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);

        let dup_fd = unsafe {
            // Safe because fcntl doesn't affect memory and client_shm should wrap a known valid
            // file descriptor.
            libc::fcntl(client_shm.as_raw_fd(), libc::F_DUPFD_CLOEXEC, 0)
        };
        if dup_fd < 0 {
            return Err(Box::new(Error::DupError(SysError::last())));
        }
        let file = unsafe {
            // safe because we checked the result of libc::fcntl()
            File::from_raw_fd(dup_fd)
        };
        let client_shm_clone = SharedMemory::from_file(file).map_err(Error::BaseMmapError)?;

        Ok(Box::new(Self {
            num_channels,
            frame_rate,
            buffer_size,
            frame_size: format.sample_bytes() * num_channels,
            interval,
            next_frame: interval,
            start_time: Instant::now(),
            stream_id,
            direction,
            vios_client,
            client_shm: client_shm_clone,
        }))
    }
}

impl ShmStream for VioSndShmStream {
    fn frame_size(&self) -> usize {
        self.frame_size
    }

    fn num_channels(&self) -> usize {
        self.num_channels
    }

    fn frame_rate(&self) -> u32 {
        self.frame_rate
    }

    /// Waits until the next time a frame should be sent to the server. The server may release the
    /// previous buffer much sooner than it needs the next one, so this function may sleep to wait
    /// for the right time.
    fn wait_for_next_action_with_timeout(
        &mut self,
        timeout: Duration,
    ) -> GenericResult<Option<ServerRequest>> {
        let elapsed = self.start_time.elapsed();
        if elapsed < self.next_frame {
            if timeout < self.next_frame - elapsed {
                std::thread::sleep(timeout);
                return Ok(None);
            } else {
                std::thread::sleep(self.next_frame - elapsed);
            }
        }
        self.next_frame += self.interval;
        Ok(Some(ServerRequest::new(self.buffer_size, self)))
    }
}

impl BufferSet for VioSndShmStream {
    fn callback(&mut self, offset: usize, frames: usize) -> GenericResult<()> {
        match self.direction {
            StreamDirection::Playback => {
                self.vios_client.inject_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
            StreamDirection::Capture => {
                self.vios_client.request_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
        }
        Ok(())
    }

    fn ignore(&mut self) -> GenericResult<()> {
        Ok(())
    }
}

impl Drop for VioSndShmStream {
    fn drop(&mut self) {
        let stream_id = self.stream_id;
        if let Err(e) = self
            .vios_client
            .stop_stream(stream_id)
            .and_then(|_| self.vios_client.release_stream(stream_id))
        {
            error!("Failed to stop and release stream {}: {}", stream_id, e);
        }
    }
}
<|endoftext|>


<commit_before>//! limit defines a struct to enforce limits.

use std::sync::atomic::AtomicUsize;

/// Represents a struct used to enforce a numerical limit.
pub struct Limit {
    upper_bound: usize,
    #[allow(unused)]
    max: AtomicUsize,
}

impl Limit {
    /// Creates a new limit.
    #[inline]
    pub const fn new(upper_bound: usize) -> Self {
        Self { upper_bound, max: AtomicUsize::new(0) }
    }

    /// Creates a new limit.
    #[inline]
    #[cfg(feature = "tracking")]
    pub const fn new_tracking(upper_bound: usize) -> Self {
        Self { upper_bound, max: AtomicUsize::new(1) }
    }

    /// Gets the underlying numeric limit.
    #[inline]
    pub const fn inner(&self) -> usize {
        self.upper_bound
    }

    /// Checks whether the given value is below the limit.
    /// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
    #[inline]
    pub fn check(&self, other: usize) -> Result<(), ()> {
        if other > self.upper_bound {
            Err(())
        } else {
            #[cfg(feature = "tracking")]
            loop {
                use std::sync::atomic::Ordering;
                let old_max = self.max.load(Ordering::Relaxed);
                if other <= old_max || old_max == 0 {
                    break;
                }
                if self
                    .max
                    .compare_exchange(old_max, other, Ordering::Relaxed, Ordering::Relaxed)
                    .is_ok()
                {
                    eprintln!("new max: {}", other);
                }
            }

            Ok(())
        }
    }
}
<commit_msg>Use `compare_exchange_weak` in `limit::Limit::check`<commit_after>//! limit defines a struct to enforce limits.

use std::sync::atomic::AtomicUsize;

/// Represents a struct used to enforce a numerical limit.
pub struct Limit {
    upper_bound: usize,
    #[allow(unused)]
    max: AtomicUsize,
}

impl Limit {
    /// Creates a new limit.
    #[inline]
    pub const fn new(upper_bound: usize) -> Self {
        Self { upper_bound, max: AtomicUsize::new(0) }
    }

    /// Creates a new limit.
    #[inline]
    #[cfg(feature = "tracking")]
    pub const fn new_tracking(upper_bound: usize) -> Self {
        Self { upper_bound, max: AtomicUsize::new(1) }
    }

    /// Gets the underlying numeric limit.
    #[inline]
    pub const fn inner(&self) -> usize {
        self.upper_bound
    }

    /// Checks whether the given value is below the limit.
    /// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
    #[inline]
    pub fn check(&self, other: usize) -> Result<(), ()> {
        if other > self.upper_bound {
            Err(())
        } else {
            #[cfg(feature = "tracking")]
            loop {
                use std::sync::atomic::Ordering;
                let old_max = self.max.load(Ordering::Relaxed);
                if other <= old_max || old_max == 0 {
                    break;
                }
                if self
                    .max
                    .compare_exchange_weak(old_max, other, Ordering::Relaxed, Ordering::Relaxed)
                    .is_ok()
                {
                    eprintln!("new max: {}", other);
                }
            }

            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>//! SGX-specific access to architectural features.
//!
//! The functionality in this module is further documented in the Intel
//! Software Developer's Manual, Volume 3, Chapter 40.
#![unstable(feature = "sgx_platform", issue = "56975")]

use mem::MaybeUninit;

/// Wrapper struct to force 16-byte alignment.
#[repr(align(16))]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Align16<T>(pub T);

/// Wrapper struct to force 128-byte alignment.
#[repr(align(128))]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Align128<T>(pub T);

/// Wrapper struct to force 512-byte alignment.
#[repr(align(512))]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Align512<T>(pub T);

const ENCLU_EREPORT: u32 = 0;
const ENCLU_EGETKEY: u32 = 1;

/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
    unsafe {
        let mut out = MaybeUninit::uninitialized();
        let error;

        asm!(
            "enclu"
            : "={eax}"(error)
            : "{eax}"(ENCLU_EGETKEY),
              "{rbx}"(request),
              "{rcx}"(out.as_mut_ptr())
            : "flags"
        );

        match error {
            0 => Ok(out.into_inner()),
            err => Err(err),
        }
    }
}

/// Call the `EREPORT` instruction.
///
/// This creates a cryptographic report describing the contents of the current
/// enclave. The report may be verified by the enclave described in
/// `targetinfo`.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn ereport(
    targetinfo: &Align512<[u8; 512]>,
    reportdata: &Align128<[u8; 64]>,
) -> Align512<[u8; 432]> {
    unsafe {
        let mut report = MaybeUninit::uninitialized();

        asm!(
            "enclu"
            : /* no output registers */
            : "{eax}"(ENCLU_EREPORT),
              "{rbx}"(targetinfo),
              "{rcx}"(reportdata),
              "{rdx}"(report.as_mut_ptr())
        );

        report.into_inner()
    }
}
<commit_msg>fix SGX build failures<commit_after>//! SGX-specific access to architectural features.
//!
//! The functionality in this module is further documented in the Intel
//! Software Developer's Manual, Volume 3, Chapter 40.
#![unstable(feature = "sgx_platform", issue = "56975")]

use mem::MaybeUninit;

/// Wrapper struct to force 16-byte alignment.
#[repr(align(16))]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Align16<T>(pub T);

/// Wrapper struct to force 128-byte alignment.
#[repr(align(128))]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Align128<T>(pub T);

/// Wrapper struct to force 512-byte alignment.
#[repr(align(512))]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Align512<T>(pub T);

const ENCLU_EREPORT: u32 = 0;
const ENCLU_EGETKEY: u32 = 1;

/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
    unsafe {
        let mut out = MaybeUninit::uninitialized();
        let error;

        asm!(
            "enclu"
            : "={eax}"(error)
            : "{eax}"(ENCLU_EGETKEY),
              "{rbx}"(request),
              "{rcx}"(out.as_mut_ptr())
            : "flags"
        );

        match error {
            0 => Ok(out.into_initialized()),
            err => Err(err),
        }
    }
}

/// Call the `EREPORT` instruction.
///
/// This creates a cryptographic report describing the contents of the current
/// enclave. The report may be verified by the enclave described in
/// `targetinfo`.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn ereport(
    targetinfo: &Align512<[u8; 512]>,
    reportdata: &Align128<[u8; 64]>,
) -> Align512<[u8; 432]> {
    unsafe {
        let mut report = MaybeUninit::uninitialized();

        asm!(
            "enclu"
            : /* no output registers */
            : "{eax}"(ENCLU_EREPORT),
              "{rbx}"(targetinfo),
              "{rcx}"(reportdata),
              "{rdx}"(report.as_mut_ptr())
        );

        report.into_initialized()
    }
}
<|endoftext|>


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

//! Error Reporting for Anonymous Region Lifetime Errors
//! where one region is named and the other is anonymous.
use infer::InferCtxt;
use infer::region_inference::RegionResolutionError::*;
use infer::region_inference::RegionResolutionError;
use ty;

impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
    // This method generates the error message for the case when
    // the function arguments consist of a named region and an anonymous
    // region and corresponds to `ConcreteFailure(..)`
    pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
        let (span, sub, sup) = match *error {
            ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
            _ => return false, // inapplicable
        };

        debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})",
               sub,
               sup);

        // Determine whether the sub and sup consist of one named region ('a)
        // and one anonymous (elided) region. If so, find the parameter arg
        // where the anonymous region appears (there must always be one; we
        // only introduced anonymous regions in parameters) as well as a
        // version new_ty of its type where the anonymous region is replaced
        // with the named one.//scope_def_id
        let (named, anon, anon_arg_info, region_info) =
            if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
               self.find_arg_with_region(sup, sub).is_some() {
                (sub,
                 sup,
                 self.find_arg_with_region(sup, sub).unwrap(),
                 self.is_suitable_region(sup).unwrap())
            } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
                      self.find_arg_with_region(sub, sup).is_some() {
                (sup,
                 sub,
                 self.find_arg_with_region(sub, sup).unwrap(),
                 self.is_suitable_region(sub).unwrap())
            } else {
                return false; // inapplicable
            };

        debug!("try_report_named_anon_conflict: named = {:?}", named);
        debug!("try_report_named_anon_conflict: anon_arg_info = {:?}",
               anon_arg_info);
        debug!("try_report_named_anon_conflict: region_info = {:?}",
               region_info);

        let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
                                                                       anon_arg_info.arg_ty,
                                                                       anon_arg_info.bound_region,
                                                                       anon_arg_info.is_first,
                                                                       region_info.def_id,
                                                                       region_info.is_impl_item);
        match br {
            ty::BrAnon(_) => {}
            _ => {
                /* not an anonymous region */
                debug!("try_report_named_anon_conflict: not an anonymous region");
                return false;
            }
        }

        if is_impl_item {
            debug!("try_report_named_anon_conflict: impl item, bail out");
            return false;
        }

        if let Some(anon_ty) = self.find_anon_type(anon, &br) {
            let (_, fndecl) = anon_ty;
            if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() ||
               self.is_self_anon(is_first, scope_def_id) {
                return false;
            }
        }

        let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
            (format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
        } else {
            ("parameter type".to_owned(), "type".to_owned())
        };

        struct_span_err!(self.tcx.sess,
                         span,
                         E0621,
                         "explicit lifetime required in {}",
                         error_var)
                .span_label(arg.pat.span,
                            format!("consider changing {} to `{}`", span_label_var, new_ty))
                .span_label(span, format!("lifetime `{}` required", named))
                .emit();
        return true;

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

//! Error Reporting for Anonymous Region Lifetime Errors
//! where one region is named and the other is anonymous.
use infer::InferCtxt;
use infer::region_inference::RegionResolutionError::*;
use infer::region_inference::RegionResolutionError;
use ty;

impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
    // This method generates the error message for the case when
    // the function arguments consist of a named region and an anonymous
    // region and corresponds to `ConcreteFailure(..)`
    pub fn try_report_named_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool {
        let (span, sub, sup) = match *error {
            ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
            _ => return false, // inapplicable
        };

        debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})",
               sub,
               sup);

        // Determine whether the sub and sup consist of one named region ('a)
        // and one anonymous (elided) region. If so, find the parameter arg
        // where the anonymous region appears (there must always be one; we
        // only introduced anonymous regions in parameters) as well as a
        // version new_ty of its type where the anonymous region is replaced
        // with the named one.//scope_def_id
        let (named, anon, anon_arg_info, region_info) =
            if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
               self.find_arg_with_region(sup, sub).is_some() {
                (sub,
                 sup,
                 self.find_arg_with_region(sup, sub).unwrap(),
                 self.is_suitable_region(sup).unwrap())
            } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
                      self.find_arg_with_region(sub, sup).is_some() {
                (sup,
                 sub,
                 self.find_arg_with_region(sub, sup).unwrap(),
                 self.is_suitable_region(sub).unwrap())
            } else {
                return false; // inapplicable
            };

        debug!("try_report_named_anon_conflict: named = {:?}", named);
        debug!("try_report_named_anon_conflict: anon_arg_info = {:?}",
               anon_arg_info);
        debug!("try_report_named_anon_conflict: region_info = {:?}",
               region_info);

        let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
                                                                       anon_arg_info.arg_ty,
                                                                       anon_arg_info.bound_region,
                                                                       anon_arg_info.is_first,
                                                                       region_info.def_id,
                                                                       region_info.is_impl_item);
        match br {
            ty::BrAnon(_) => {}
            _ => {
                /* not an anonymous region */
                debug!("try_report_named_anon_conflict: not an anonymous region");
                return false;
            }
        }

        if is_impl_item {
            debug!("try_report_named_anon_conflict: impl item, bail out");
            return false;
        }

        if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
            if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() ||
               self.is_self_anon(is_first, scope_def_id) {
                return false;
            }
        }

        let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
            (format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
        } else {
            ("parameter type".to_owned(), "type".to_owned())
        };

        struct_span_err!(self.tcx.sess,
                         span,
                         E0621,
                         "explicit lifetime required in {}",
                         error_var)
                .span_label(arg.pat.span,
                            format!("consider changing {} to `{}`", span_label_var, new_ty))
                .span_label(span, format!("lifetime `{}` required", named))
                .emit();
        return true;

    }
}
<|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/. */

use dom::bindings::callback::ExceptionHandling::Rethrow;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilterConstants;
use dom::bindings::codegen::Bindings::NodeIteratorBinding;
use dom::bindings::codegen::Bindings::NodeIteratorBinding::NodeIteratorMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::Document;
use dom::node::Node;
use std::cell::Cell;
use std::rc::Rc;

#[dom_struct]
pub struct NodeIterator {
    reflector_: Reflector,
    root_node: JS<Node>,
    #[ignore_heap_size_of = "Defined in rust-mozjs"]
    reference_node: MutHeap<JS<Node>>,
    pointer_before_reference_node: Cell<bool>,
    what_to_show: u32,
    #[ignore_heap_size_of = "Can't measure due to #6870"]
    filter: Filter,
}

impl NodeIterator {
    fn new_inherited(root_node: &Node,
                     what_to_show: u32,
                     filter: Filter) -> NodeIterator {
        NodeIterator {
            reflector_: Reflector::new(),
            root_node: JS::from_ref(root_node),
            reference_node: MutHeap::new(root_node),
            pointer_before_reference_node: Cell::new(true),
            what_to_show: what_to_show,
            filter: filter
        }
    }

    pub fn new_with_filter(document: &Document,
                           root_node: &Node,
                           what_to_show: u32,
                           filter: Filter) -> Root<NodeIterator> {
        reflect_dom_object(box NodeIterator::new_inherited(root_node, what_to_show, filter),
                           GlobalRef::Window(document.window()),
                           NodeIteratorBinding::Wrap)
    }

    pub fn new(document: &Document,
               root_node: &Node,
               what_to_show: u32,
               node_filter: Option<Rc<NodeFilter>>) -> Root<NodeIterator> {
        let filter = match node_filter {
            None => Filter::None,
            Some(jsfilter) => Filter::Callback(jsfilter)
        };
        NodeIterator::new_with_filter(document, root_node, what_to_show, filter)
    }
}

impl NodeIteratorMethods for NodeIterator {
    // https://dom.spec.whatwg.org/#dom-nodeiterator-root
    fn Root(&self) -> Root<Node> {
        self.root_node.root()
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-whattoshow
    fn WhatToShow(&self) -> u32 {
        self.what_to_show
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-filter
    fn GetFilter(&self) -> Option<Rc<NodeFilter>> {
        match self.filter {
            Filter::None => None,
            Filter::Callback(ref nf) => Some((*nf).clone()),
            Filter::Native(_) => panic!("Cannot convert native node filter to DOM NodeFilter")
        }
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-referencenode
    fn ReferenceNode(&self) -> Root<Node> {
        self.reference_node.get()
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-pointerbeforereferencenode
    fn PointerBeforeReferenceNode(&self) -> bool {
        self.pointer_before_reference_node.get()
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-nextnode
    fn NextNode(&self) -> Fallible<Option<Root<Node>>> {
        // https://dom.spec.whatwg.org/#concept-NodeIterator-traverse
        // Step 1.
        let node = self.reference_node.get();

        // Step 2.
        let mut before_node = self.pointer_before_reference_node.get();

        // Step 3-1.
        if before_node {
            before_node = false;

            // Step 3-2.
            let result = try!(self.accept_node(node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(node));
            }
        }

        // Step 3-1.
        for following_node in node.r().following_nodes(self.root_node.root().r()) {
            // Step 3-2.
            let result = try!(self.accept_node(following_node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(following_node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(following_node));
            }
        }

        Ok(None)
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-previousnode
    fn PreviousNode(&self) -> Fallible<Option<Root<Node>>> {
        // https://dom.spec.whatwg.org/#concept-NodeIterator-traverse
        // Step 1.
        let node = self.reference_node.get();

        // Step 2.
        let mut before_node = self.pointer_before_reference_node.get();

        // Step 3-1.
        if !before_node {
            before_node = true;

            // Step 3-2.
            let result = try!(self.accept_node(node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(node));
            }
        }

        // Step 3-1.
        for preceding_node in node.r().preceding_nodes(self.root_node.root().r()) {

            // Step 3-2.
            let result = try!(self.accept_node(preceding_node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(preceding_node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(preceding_node));
            }
        }

        Ok(None)
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-detach
    fn Detach(&self) {
        // This method intentionally left blank.
    }
}

impl NodeIterator {
    // https://dom.spec.whatwg.org/#concept-node-filter
    fn accept_node(&self, node: &Node) -> Fallible<u16> {
        // Step 1.
        let n = node.NodeType() - 1;
        // Step 2.
        if (self.what_to_show & (1 << n)) == 0 {
            return Ok(NodeFilterConstants::FILTER_SKIP)
        }
        // Step 3-5.
        match self.filter {
            Filter::None => Ok(NodeFilterConstants::FILTER_ACCEPT),
            Filter::Native(f) => Ok((f)(node)),
            Filter::Callback(ref callback) => callback.AcceptNode_(self, node, Rethrow)
        }
    }
}

#[derive(JSTraceable)]
pub enum Filter {
    None,
    Native(fn (node: &Node) -> u16),
    Callback(Rc<NodeFilter>)
}
<commit_msg>Do not root NodeIterator::root_node<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/. */

use dom::bindings::callback::ExceptionHandling::Rethrow;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilterConstants;
use dom::bindings::codegen::Bindings::NodeIteratorBinding;
use dom::bindings::codegen::Bindings::NodeIteratorBinding::NodeIteratorMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::Document;
use dom::node::Node;
use std::cell::Cell;
use std::rc::Rc;

#[dom_struct]
pub struct NodeIterator {
    reflector_: Reflector,
    root_node: JS<Node>,
    #[ignore_heap_size_of = "Defined in rust-mozjs"]
    reference_node: MutHeap<JS<Node>>,
    pointer_before_reference_node: Cell<bool>,
    what_to_show: u32,
    #[ignore_heap_size_of = "Can't measure due to #6870"]
    filter: Filter,
}

impl NodeIterator {
    fn new_inherited(root_node: &Node,
                     what_to_show: u32,
                     filter: Filter) -> NodeIterator {
        NodeIterator {
            reflector_: Reflector::new(),
            root_node: JS::from_ref(root_node),
            reference_node: MutHeap::new(root_node),
            pointer_before_reference_node: Cell::new(true),
            what_to_show: what_to_show,
            filter: filter
        }
    }

    pub fn new_with_filter(document: &Document,
                           root_node: &Node,
                           what_to_show: u32,
                           filter: Filter) -> Root<NodeIterator> {
        reflect_dom_object(box NodeIterator::new_inherited(root_node, what_to_show, filter),
                           GlobalRef::Window(document.window()),
                           NodeIteratorBinding::Wrap)
    }

    pub fn new(document: &Document,
               root_node: &Node,
               what_to_show: u32,
               node_filter: Option<Rc<NodeFilter>>) -> Root<NodeIterator> {
        let filter = match node_filter {
            None => Filter::None,
            Some(jsfilter) => Filter::Callback(jsfilter)
        };
        NodeIterator::new_with_filter(document, root_node, what_to_show, filter)
    }
}

impl NodeIteratorMethods for NodeIterator {
    // https://dom.spec.whatwg.org/#dom-nodeiterator-root
    fn Root(&self) -> Root<Node> {
        self.root_node.root()
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-whattoshow
    fn WhatToShow(&self) -> u32 {
        self.what_to_show
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-filter
    fn GetFilter(&self) -> Option<Rc<NodeFilter>> {
        match self.filter {
            Filter::None => None,
            Filter::Callback(ref nf) => Some((*nf).clone()),
            Filter::Native(_) => panic!("Cannot convert native node filter to DOM NodeFilter")
        }
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-referencenode
    fn ReferenceNode(&self) -> Root<Node> {
        self.reference_node.get()
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-pointerbeforereferencenode
    fn PointerBeforeReferenceNode(&self) -> bool {
        self.pointer_before_reference_node.get()
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-nextnode
    fn NextNode(&self) -> Fallible<Option<Root<Node>>> {
        // https://dom.spec.whatwg.org/#concept-NodeIterator-traverse
        // Step 1.
        let node = self.reference_node.get();

        // Step 2.
        let mut before_node = self.pointer_before_reference_node.get();

        // Step 3-1.
        if before_node {
            before_node = false;

            // Step 3-2.
            let result = try!(self.accept_node(node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(node));
            }
        }

        // Step 3-1.
        for following_node in node.r().following_nodes(&self.root_node) {
            // Step 3-2.
            let result = try!(self.accept_node(following_node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(following_node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(following_node));
            }
        }

        Ok(None)
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-previousnode
    fn PreviousNode(&self) -> Fallible<Option<Root<Node>>> {
        // https://dom.spec.whatwg.org/#concept-NodeIterator-traverse
        // Step 1.
        let node = self.reference_node.get();

        // Step 2.
        let mut before_node = self.pointer_before_reference_node.get();

        // Step 3-1.
        if !before_node {
            before_node = true;

            // Step 3-2.
            let result = try!(self.accept_node(node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(node));
            }
        }

        // Step 3-1.
        for preceding_node in node.r().preceding_nodes(&self.root_node) {

            // Step 3-2.
            let result = try!(self.accept_node(preceding_node.r()));

            // Step 3-3.
            if result == NodeFilterConstants::FILTER_ACCEPT {
                // Step 4.
                self.reference_node.set(preceding_node.r());
                self.pointer_before_reference_node.set(before_node);

                return Ok(Some(preceding_node));
            }
        }

        Ok(None)
    }

    // https://dom.spec.whatwg.org/#dom-nodeiterator-detach
    fn Detach(&self) {
        // This method intentionally left blank.
    }
}

impl NodeIterator {
    // https://dom.spec.whatwg.org/#concept-node-filter
    fn accept_node(&self, node: &Node) -> Fallible<u16> {
        // Step 1.
        let n = node.NodeType() - 1;
        // Step 2.
        if (self.what_to_show & (1 << n)) == 0 {
            return Ok(NodeFilterConstants::FILTER_SKIP)
        }
        // Step 3-5.
        match self.filter {
            Filter::None => Ok(NodeFilterConstants::FILTER_ACCEPT),
            Filter::Native(f) => Ok((f)(node)),
            Filter::Callback(ref callback) => callback.AcceptNode_(self, node, Rethrow)
        }
    }
}

#[derive(JSTraceable)]
pub enum Filter {
    None,
    Native(fn (node: &Node) -> u16),
    Callback(Rc<NodeFilter>)
}
<|endoftext|>


<commit_before>
struct median_filter_t<'a> {
    window: &'a mut Vec<u8>,
    input: &'a mut Vec<u8>,
    hole: i64,
    max: i64,
}

fn median_init(f: &mut median_filter_t, w_size: usize){
    f.max = 0;
    f.hole = 0;

    *f.window = Vec::with_capacity(w_size);
    *f.input = Vec::with_capacity(w_size/2);
}

fn median_close_hole(f: &mut median_filter_t) {
    while f.hole < f.max - 1 {
        let i: usize = f.hole as usize;
        f.window[i] = f.window[i + 1];
        f.hole += 1;
    }

    if f.hole == f.max - 1 {
        f.max = f.max - 1;
    }
}

fn media_remove(f: &mut median_filter_t, v: u8) {
    median_close_hole(f);

    let mut lo: i64 = 0;
    let mut hi: i64 = f.max - 1;

    f.hole = (hi / 2) as i64;

    while lo <= hi {
        let i: usize = f.hole as usize;
        if v > f.window[i] {
            lo = f.hole + 1;
        } else if v < f.window[i] {
            hi = f.hole - 1;
        } else {
            break;
        }
        f.hole = (lo + hi) / 2;
    }
}

fn median_add(f: &mut median_filter_t, v: u8) {
    if f.hole == f.max {
        f.max += 1;
    }

    let mut i: usize = f.hole as usize;
    while (f.hole > 0) && (f.window[i] > v) {
        f.window[i] = f.window[i-1];
        f.hole -= 1;
        i = f.hole as usize;
    }

    i = f.hole as usize;

    while (f.hole < f.max - 1) && (f.window[i+1] < v) {
        f.window[i] = f.window[i+1];
        f.hole += 1;
        i = f.hole as usize;
    }

    f.window[i] = v;
    f.hole = f.max;
}

fn median_get(f: &mut median_filter_t) -> u8 {
    median_close_hole(f);

    if f.max == 0 {
        return 0;
    }

    if (f.max & 1i64) == 1 {
        let i: usize = f.max as usize;
        return f.window[(i-1)/2];
    } else {
        let i: usize = f.max as usize;
        return (f.window[(i-1)/2] + f.window[i/2]) / 2;
    }
}

fn median_filter(input: &mut Vec<u8>, size: i64, w_size: i64) -> i32 {
    return 0;
}

fn main() {
    println!("Hello, world!");
}
<commit_msg>remove median init function, add median_filter function and change type of vectors in structure<commit_after>
struct median_filter_t {
    window: Vec<u8>,
    input: Vec<u8>,
    hole: i64,
    max: i64,
}

fn median_close_hole(f: &mut median_filter_t) {
    while f.hole < f.max - 1 {
        let i: usize = f.hole as usize;
        f.window[i] = f.window[i + 1];
        f.hole += 1;
    }

    if f.hole == f.max - 1 {
        f.max = f.max - 1;
    }
}

fn media_remove(f: &mut median_filter_t, v: u8) {
    median_close_hole(f);

    let mut lo: i64 = 0;
    let mut hi: i64 = f.max - 1;

    f.hole = (hi / 2) as i64;

    while lo <= hi {
        let i: usize = f.hole as usize;
        if v > f.window[i] {
            lo = f.hole + 1;
        } else if v < f.window[i] {
            hi = f.hole - 1;
        } else {
            break;
        }
        f.hole = (lo + hi) / 2;
    }
}

fn median_add(f: &mut median_filter_t, v: u8) {
    if f.hole == f.max {
        f.max += 1;
    }

    let mut i: usize = f.hole as usize;
    while (f.hole > 0) && (f.window[i] > v) {
        f.window[i] = f.window[i-1];
        f.hole -= 1;
        i = f.hole as usize;
    }

    i = f.hole as usize;

    while (f.hole < f.max - 1) && (f.window[i+1] < v) {
        f.window[i] = f.window[i+1];
        f.hole += 1;
        i = f.hole as usize;
    }

    f.window[i] = v;
    f.hole = f.max;
}

fn median_get(f: &mut median_filter_t) -> u8 {
    median_close_hole(f);

    if f.max == 0 {
        return 0;
    }

    if (f.max & 1i64) == 1 {
        let i: usize = f.max as usize;
        return f.window[(i-1)/2];
    } else {
        let i: usize = f.max as usize;
        return (f.window[(i-1)/2] + f.window[i/2]) / 2;
    }
}

fn median_filter(input: &mut Vec<u8>, size: usize, w_size: usize) -> i32 {
    let mut f: median_filter_t = median_filter_t{ max: 0, hole: 0, window: vec![0; w_size], input: vec![0, (w_size/2) as u8]};
    let mut i: usize = 0;
    let mut start: i64 = -(w_size as i64);
    let mut end: usize = 0;
    let tmp: i64 = w_size as i64;
    let mut pos: i64 = -(tmp - (tmp/2)) + 1;

    while pos < size as i64 {
        if start >= 0 {
            let temp: u8 = f.input[i];
            media_remove(&mut f, temp);
        }

        if end < size {
            median_add(&mut f, input[end]);
        }

        if pos >= 0 {
            f.input[i] = input[pos as usize];
            if !((i+1) < (w_size / 2)) {
                i = 0;
            }
            input[pos as usize] = median_get(&mut f);
        }
        start += 1;
        end += 1;
        pos += 1;
    }

    return 0;
}

fn main() {
    println!("Hello, world!");
}
<|endoftext|>


<commit_before>fn main()
{
	println!("Hello, GUI world!")
}
<commit_msg>Extern crate<commit_after>extern crate core;

fn main()
{
	println!("Hello, GUI world!")
}
<|endoftext|>


<commit_before>//! For middleware documentation, see [`ErrorHandlers`].

use std::{
    future::Future,
    pin::Pin,
    rc::Rc,
    task::{Context, Poll},
};

use actix_service::{Service, Transform};
use ahash::AHashMap;
use futures_core::{future::LocalBoxFuture, ready};
use pin_project_lite::pin_project;

use crate::{
    body::EitherBody,
    dev::{ServiceRequest, ServiceResponse},
    http::StatusCode,
    Error, Result,
};

/// Return type for [`ErrorHandlers`] custom handlers.
pub enum ErrorHandlerResponse<B> {
    /// Immediate HTTP response.
    Response(ServiceResponse<EitherBody<B>>),

    /// A future that resolves to an HTTP response.
    Future(LocalBoxFuture<'static, Result<ServiceResponse<EitherBody<B>>, Error>>),
}

type ErrorHandler<B> = dyn Fn(ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>>;

/// Middleware for registering custom status code based error handlers.
///
/// Register handlers with the `ErrorHandlers::handler()` method to register a custom error handler
/// for a given status code. Handlers can modify existing responses or create completely new ones.
///
/// # Examples
/// ```
/// use actix_web::middleware::{ErrorHandlers, ErrorHandlerResponse};
/// use actix_web::{web, dev, App, HttpRequest, HttpResponse, Result};
/// use actix_web::http::{StatusCode, header};
///
/// fn render_500<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
///     res.response_mut()
///        .headers_mut()
///        .insert(header::CONTENT_TYPE, header::HeaderValue::from_static("Error"));
///
///     Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
/// }
///
/// let app = App::new()
///     .wrap(
///         ErrorHandlers::new()
///             .handler(StatusCode::INTERNAL_SERVER_ERROR, render_500),
///     )
///     .service(web::resource("/test")
///         .route(web::get().to(|| HttpResponse::Ok()))
///         .route(web::head().to(|| HttpResponse::MethodNotAllowed())
///     ));
/// ```
pub struct ErrorHandlers<B> {
    handlers: Handlers<B>,
}

type Handlers<B> = Rc<AHashMap<StatusCode, Box<ErrorHandler<B>>>>;

impl<B> Default for ErrorHandlers<B> {
    fn default() -> Self {
        ErrorHandlers {
            handlers: Default::default(),
        }
    }
}

impl<B> ErrorHandlers<B> {
    /// Construct new `ErrorHandlers` instance.
    pub fn new() -> Self {
        ErrorHandlers::default()
    }

    /// Register error handler for specified status code.
    pub fn handler<F>(mut self, status: StatusCode, handler: F) -> Self
    where
        F: Fn(ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> + 'static,
    {
        Rc::get_mut(&mut self.handlers)
            .unwrap()
            .insert(status, Box::new(handler));
        self
    }
}

impl<S, B> Transform<S, ServiceRequest> for ErrorHandlers<B>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<EitherBody<B>>;
    type Error = Error;
    type Transform = ErrorHandlersMiddleware<S, B>;
    type InitError = ();
    type Future = LocalBoxFuture<'static, Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        let handlers = self.handlers.clone();
        Box::pin(async move { Ok(ErrorHandlersMiddleware { service, handlers }) })
    }
}

#[doc(hidden)]
pub struct ErrorHandlersMiddleware<S, B> {
    service: S,
    handlers: Handlers<B>,
}

impl<S, B> Service<ServiceRequest> for ErrorHandlersMiddleware<S, B>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<EitherBody<B>>;
    type Error = Error;
    type Future = ErrorHandlersFuture<S::Future, B>;

    actix_service::forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let handlers = self.handlers.clone();
        let fut = self.service.call(req);
        ErrorHandlersFuture::ServiceFuture { fut, handlers }
    }
}

pin_project! {
    #[project = ErrorHandlersProj]
    pub enum ErrorHandlersFuture<Fut, B>
    where
        Fut: Future,
    {
        ServiceFuture {
            #[pin]
            fut: Fut,
            handlers: Handlers<B>,
        },
        ErrorHandlerFuture {
            fut: LocalBoxFuture<'static, Result<ServiceResponse<EitherBody<B>>, Error>>,
        },
    }
}

impl<Fut, B> Future for ErrorHandlersFuture<Fut, B>
where
    Fut: Future<Output = Result<ServiceResponse<B>, Error>>,
{
    type Output = Result<ServiceResponse<EitherBody<B>>, Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        match self.as_mut().project() {
            ErrorHandlersProj::ServiceFuture { fut, handlers } => {
                let res = ready!(fut.poll(cx))?;

                match handlers.get(&res.status()) {
                    Some(handler) => match handler(res)? {
                        ErrorHandlerResponse::Response(res) => Poll::Ready(Ok(res)),
                        ErrorHandlerResponse::Future(fut) => {
                            self.as_mut()
                                .set(ErrorHandlersFuture::ErrorHandlerFuture { fut });

                            self.poll(cx)
                        }
                    },

                    None => Poll::Ready(Ok(res.map_into_left_body())),
                }
            }

            ErrorHandlersProj::ErrorHandlerFuture { fut } => fut.as_mut().poll(cx),
        }
    }
}

#[cfg(test)]
mod tests {
    use actix_service::IntoService;
    use actix_utils::future::ok;
    use bytes::Bytes;
    use futures_util::future::FutureExt as _;

    use super::*;
    use crate::{
        http::{
            header::{HeaderValue, CONTENT_TYPE},
            StatusCode,
        },
        test::{self, TestRequest},
    };

    #[actix_rt::test]
    async fn add_header_error_handler() {
        #[allow(clippy::unnecessary_wraps)]
        fn error_handler<B>(mut res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
            res.response_mut()
                .headers_mut()
                .insert(CONTENT_TYPE, HeaderValue::from_static("0001"));

            Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
        }

        let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR);

        let mw = ErrorHandlers::new()
            .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
            .new_transform(srv.into_service())
            .await
            .unwrap();

        let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
        assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
    }

    #[actix_rt::test]
    async fn add_header_error_handler_async() {
        #[allow(clippy::unnecessary_wraps)]
        fn error_handler<B: 'static>(
            mut res: ServiceResponse<B>,
        ) -> Result<ErrorHandlerResponse<B>> {
            res.response_mut()
                .headers_mut()
                .insert(CONTENT_TYPE, HeaderValue::from_static("0001"));

            Ok(ErrorHandlerResponse::Future(
                ok(res.map_into_left_body()).boxed_local(),
            ))
        }

        let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR);

        let mw = ErrorHandlers::new()
            .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
            .new_transform(srv.into_service())
            .await
            .unwrap();

        let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
        assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
    }

    #[actix_rt::test]
    async fn changes_body_type() {
        #[allow(clippy::unnecessary_wraps)]
        fn error_handler<B: 'static>(
            res: ServiceResponse<B>,
        ) -> Result<ErrorHandlerResponse<B>> {
            let (req, res) = res.into_parts();
            let res = res.set_body(Bytes::from("sorry, that's no bueno"));

            let res = ServiceResponse::new(req, res)
                .map_into_boxed_body()
                .map_into_right_body();

            Ok(ErrorHandlerResponse::Response(res))
        }

        let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR);

        let mw = ErrorHandlers::new()
            .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
            .new_transform(srv.into_service())
            .await
            .unwrap();

        let res = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
        assert_eq!(test::read_body(res).await, "sorry, that's no bueno");
    }

    // TODO: test where error is thrown
}
<commit_msg>Improve module docs for error handler middleware (#2543)<commit_after>//! For middleware documentation, see [`ErrorHandlers`].

use std::{
    future::Future,
    pin::Pin,
    rc::Rc,
    task::{Context, Poll},
};

use actix_service::{Service, Transform};
use ahash::AHashMap;
use futures_core::{future::LocalBoxFuture, ready};
use pin_project_lite::pin_project;

use crate::{
    body::EitherBody,
    dev::{ServiceRequest, ServiceResponse},
    http::StatusCode,
    Error, Result,
};

/// Return type for [`ErrorHandlers`] custom handlers.
pub enum ErrorHandlerResponse<B> {
    /// Immediate HTTP response.
    Response(ServiceResponse<EitherBody<B>>),

    /// A future that resolves to an HTTP response.
    Future(LocalBoxFuture<'static, Result<ServiceResponse<EitherBody<B>>, Error>>),
}

type ErrorHandler<B> = dyn Fn(ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>>;

/// Middleware for registering custom status code based error handlers.
///
/// Register handlers with the `ErrorHandlers::handler()` method to register a custom error handler
/// for a given status code. Handlers can modify existing responses or create completely new ones.
///
/// # Examples
/// ```
/// use actix_web::http::{header, StatusCode};
/// use actix_web::middleware::{ErrorHandlerResponse, ErrorHandlers};
/// use actix_web::{dev, web, App, HttpResponse, Result};
///
/// fn add_error_header<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
///     res.response_mut().headers_mut().insert(
///         header::CONTENT_TYPE,
///         header::HeaderValue::from_static("Error"),
///     );
///     Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
/// }
///
/// let app = App::new()
///     .wrap(ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, add_error_header))
///     .service(web::resource("/").route(web::get().to(HttpResponse::InternalServerError)));
/// ```
pub struct ErrorHandlers<B> {
    handlers: Handlers<B>,
}

type Handlers<B> = Rc<AHashMap<StatusCode, Box<ErrorHandler<B>>>>;

impl<B> Default for ErrorHandlers<B> {
    fn default() -> Self {
        ErrorHandlers {
            handlers: Default::default(),
        }
    }
}

impl<B> ErrorHandlers<B> {
    /// Construct new `ErrorHandlers` instance.
    pub fn new() -> Self {
        ErrorHandlers::default()
    }

    /// Register error handler for specified status code.
    pub fn handler<F>(mut self, status: StatusCode, handler: F) -> Self
    where
        F: Fn(ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> + 'static,
    {
        Rc::get_mut(&mut self.handlers)
            .unwrap()
            .insert(status, Box::new(handler));
        self
    }
}

impl<S, B> Transform<S, ServiceRequest> for ErrorHandlers<B>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<EitherBody<B>>;
    type Error = Error;
    type Transform = ErrorHandlersMiddleware<S, B>;
    type InitError = ();
    type Future = LocalBoxFuture<'static, Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        let handlers = self.handlers.clone();
        Box::pin(async move { Ok(ErrorHandlersMiddleware { service, handlers }) })
    }
}

#[doc(hidden)]
pub struct ErrorHandlersMiddleware<S, B> {
    service: S,
    handlers: Handlers<B>,
}

impl<S, B> Service<ServiceRequest> for ErrorHandlersMiddleware<S, B>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<EitherBody<B>>;
    type Error = Error;
    type Future = ErrorHandlersFuture<S::Future, B>;

    actix_service::forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let handlers = self.handlers.clone();
        let fut = self.service.call(req);
        ErrorHandlersFuture::ServiceFuture { fut, handlers }
    }
}

pin_project! {
    #[project = ErrorHandlersProj]
    pub enum ErrorHandlersFuture<Fut, B>
    where
        Fut: Future,
    {
        ServiceFuture {
            #[pin]
            fut: Fut,
            handlers: Handlers<B>,
        },
        ErrorHandlerFuture {
            fut: LocalBoxFuture<'static, Result<ServiceResponse<EitherBody<B>>, Error>>,
        },
    }
}

impl<Fut, B> Future for ErrorHandlersFuture<Fut, B>
where
    Fut: Future<Output = Result<ServiceResponse<B>, Error>>,
{
    type Output = Result<ServiceResponse<EitherBody<B>>, Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        match self.as_mut().project() {
            ErrorHandlersProj::ServiceFuture { fut, handlers } => {
                let res = ready!(fut.poll(cx))?;

                match handlers.get(&res.status()) {
                    Some(handler) => match handler(res)? {
                        ErrorHandlerResponse::Response(res) => Poll::Ready(Ok(res)),
                        ErrorHandlerResponse::Future(fut) => {
                            self.as_mut()
                                .set(ErrorHandlersFuture::ErrorHandlerFuture { fut });

                            self.poll(cx)
                        }
                    },

                    None => Poll::Ready(Ok(res.map_into_left_body())),
                }
            }

            ErrorHandlersProj::ErrorHandlerFuture { fut } => fut.as_mut().poll(cx),
        }
    }
}

#[cfg(test)]
mod tests {
    use actix_service::IntoService;
    use actix_utils::future::ok;
    use bytes::Bytes;
    use futures_util::future::FutureExt as _;

    use super::*;
    use crate::{
        http::{
            header::{HeaderValue, CONTENT_TYPE},
            StatusCode,
        },
        test::{self, TestRequest},
    };

    #[actix_rt::test]
    async fn add_header_error_handler() {
        #[allow(clippy::unnecessary_wraps)]
        fn error_handler<B>(mut res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
            res.response_mut()
                .headers_mut()
                .insert(CONTENT_TYPE, HeaderValue::from_static("0001"));

            Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
        }

        let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR);

        let mw = ErrorHandlers::new()
            .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
            .new_transform(srv.into_service())
            .await
            .unwrap();

        let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
        assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
    }

    #[actix_rt::test]
    async fn add_header_error_handler_async() {
        #[allow(clippy::unnecessary_wraps)]
        fn error_handler<B: 'static>(
            mut res: ServiceResponse<B>,
        ) -> Result<ErrorHandlerResponse<B>> {
            res.response_mut()
                .headers_mut()
                .insert(CONTENT_TYPE, HeaderValue::from_static("0001"));

            Ok(ErrorHandlerResponse::Future(
                ok(res.map_into_left_body()).boxed_local(),
            ))
        }

        let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR);

        let mw = ErrorHandlers::new()
            .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
            .new_transform(srv.into_service())
            .await
            .unwrap();

        let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
        assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
    }

    #[actix_rt::test]
    async fn changes_body_type() {
        #[allow(clippy::unnecessary_wraps)]
        fn error_handler<B: 'static>(
            res: ServiceResponse<B>,
        ) -> Result<ErrorHandlerResponse<B>> {
            let (req, res) = res.into_parts();
            let res = res.set_body(Bytes::from("sorry, that's no bueno"));

            let res = ServiceResponse::new(req, res)
                .map_into_boxed_body()
                .map_into_right_body();

            Ok(ErrorHandlerResponse::Response(res))
        }

        let srv = test::simple_service(StatusCode::INTERNAL_SERVER_ERROR);

        let mw = ErrorHandlers::new()
            .handler(StatusCode::INTERNAL_SERVER_ERROR, error_handler)
            .new_transform(srv.into_service())
            .await
            .unwrap();

        let res = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
        assert_eq!(test::read_body(res).await, "sorry, that's no bueno");
    }

    // TODO: test where error is thrown
}
<|endoftext|>


<commit_before>extern crate opencorpora;

use opencorpora::Dict;

fn main() {
    use std::fs::File;
    let file = File::open("dict/dict.xml").unwrap();
    match Dict::read_from_xml(&file) {
        Ok(dict) => {
            println!("Version: {}", dict.version);
            println!("Revision: {}", dict.revision);
            println!("Grammemes count: {}", dict.grammemes.len());
            println!("Restrictions count: {}", dict.restrictions.len());
            println!("Lemmata count: {}", dict.lemmata.len());
            let mut forms_count = 0;
            let mut max_forms_in_lemma = 0;
            let mut max_grammemes_in_form = 0;
            for lemma in &dict.lemmata {
                let forms = lemma.forms.len();
                forms_count += forms;
                if max_forms_in_lemma < forms {
                    max_forms_in_lemma = forms;
                }

                let lemma_grammemes = lemma.grammemes.len();
                for form in &lemma.forms {
                    let form_grammemes = form.grammemes.len();
                    let total_grammemes = lemma_grammemes + form_grammemes;
                    if max_grammemes_in_form < total_grammemes {
                        max_grammemes_in_form = total_grammemes;
                    }
                }
            }
            println!("All forms count: {}", forms_count);
            println!("Max forms in a lemma: {}", max_forms_in_lemma);
            println!("Max grammemes in a form: {}", max_grammemes_in_form);
            println!("Link types count: {}", dict.link_kinds.len());
            println!("Links count: {}", dict.links.len());
        },
        Err(e) => {
            println!("ERROR: {}", e);
        }
    }
}
<commit_msg>Исправлен путь к словарю в примере 'examples/stats.rs'.<commit_after>extern crate opencorpora;

use opencorpora::Dict;

fn main() {
    use std::fs::File;
    let file = File::open("dict/test_dict.xml").unwrap();
    match Dict::read_from_xml(&file) {
        Ok(dict) => {
            println!("Version: {}", dict.version);
            println!("Revision: {}", dict.revision);
            println!("Grammemes count: {}", dict.grammemes.len());
            println!("Restrictions count: {}", dict.restrictions.len());
            println!("Lemmata count: {}", dict.lemmata.len());
            let mut forms_count = 0;
            let mut max_forms_in_lemma = 0;
            let mut max_grammemes_in_form = 0;
            for lemma in &dict.lemmata {
                let forms = lemma.forms.len();
                forms_count += forms;
                if max_forms_in_lemma < forms {
                    max_forms_in_lemma = forms;
                }

                let lemma_grammemes = lemma.grammemes.len();
                for form in &lemma.forms {
                    let form_grammemes = form.grammemes.len();
                    let total_grammemes = lemma_grammemes + form_grammemes;
                    if max_grammemes_in_form < total_grammemes {
                        max_grammemes_in_form = total_grammemes;
                    }
                }
            }
            println!("All forms count: {}", forms_count);
            println!("Max forms in a lemma: {}", max_forms_in_lemma);
            println!("Max grammemes in a form: {}", max_grammemes_in_form);
            println!("Link types count: {}", dict.link_kinds.len());
            println!("Links count: {}", dict.links.len());
        }
        Err(e) => {
            println!("ERROR: {}", e);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(io)]

extern crate pretty;

use pretty::{
    Doc
};
use std::old_io as io;
use std::str;

#[derive(Clone, Debug)]
pub struct Forest<'a>(&'a [Tree<'a>]);

impl<'a> Forest<'a> {
    fn forest(forest: &'a [Tree<'a>]) -> Forest<'a> {
        Forest(forest)
    }

    fn nil() -> Forest<'a> {
        Forest(&[])
    }

    fn bracket(&self) -> Doc {
        if (self.0).len() == 0 {
            Doc::nil()
        } else {
            Doc::text("[")
                .append(
                    Doc::newline()
                        .append(self.pretty())
                        .nest(2))
                .append(Doc::newline())
                .append(Doc::text("]"))
        }
    }

    fn pretty(&self) -> Doc {
        let forest = self.0;
        let mut doc = Doc::nil();
        let mut i = 0;
        let k = forest.len() - 1;
        loop {
            if i < k {
                doc = doc
                    .append(forest[i].pretty()
                            .append(Doc::text(","))
                            .append(Doc::newline()));

            }
            else if i == k {
                doc = doc
                    .append(forest[i].pretty());
                break
            }
            i += 1;
        }
        doc
    }
}

#[derive(Clone, Debug)]
pub struct Tree<'a> {
    node: String,
    forest: Forest<'a>,
}

impl<'a> Tree<'a> {
    pub fn node(node: &str) -> Tree<'a> {
        Tree {
            node: node.to_string(),
            forest: Forest::nil(),
        }
    }

    pub fn node_with_forest(node: &str, forest: &'a [Tree<'a>]) -> Tree<'a> {
        Tree {
            node: node.to_string(),
            forest: Forest::forest(forest),
        }
    }

    pub fn pretty(&self) -> Doc {
        Doc::text(self.node.clone())
            .append((self.forest).bracket())
            .group()
    }
}

#[allow(dead_code)]
pub fn main() {
    let bbbbbbs = [
        Tree::node("ccc"),
        Tree::node("dd"),
    ];
    let ffffs = [
        Tree::node("gg"),
        Tree::node("hhh"),
        Tree::node("ii"),
    ];
    let aaas = [
        Tree::node_with_forest("bbbbbb", &bbbbbbs),
        Tree::node("eee"),
        Tree::node_with_forest("ffff", &ffffs),
    ];
    let example = Tree::node_with_forest("aaaa", &aaas);

    let err_msg = "<buffer is not a utf-8 encoded string>";

    // try writing to stdout
    {
        print!("\nwriting to stdout directly:\n");
        let mut out = io::stdout();
        example
            .pretty()
            .render(70, &mut out)
    // try writing to memory
    }.and_then(|()| {
        print!("\nwriting to string then printing:\n");
        let mut mem = io::MemWriter::new();
        example
            .pretty()
            .render(70, &mut mem)
            // print to console from memory
            .map(|()| {
                let res = str::from_utf8(mem.get_ref()).unwrap_or(err_msg);
                println!("{}", res)
            })
    // print an error if anything failed
    }).unwrap_or_else(|err| {
        println!("error: {}", err)
    });
}
<commit_msg>Formatting<commit_after>#![feature(io)]

extern crate pretty;

use pretty::{
    Doc
};
use std::old_io as io;
use std::str;

#[derive(Clone, Debug)]
pub struct Forest<'a>(&'a [Tree<'a>]);

impl<'a> Forest<'a> {
    fn forest(forest: &'a [Tree<'a>]) -> Forest<'a> {
        Forest(forest)
    }

    fn nil() -> Forest<'a> {
        Forest(&[])
    }

    fn bracket(&self) -> Doc {
        if (self.0).len() == 0 {
            Doc::nil()
        } else {
            Doc::text("[")
                .append(
                    Doc::newline()
                        .append(self.pretty())
                        .nest(2))
                .append(Doc::newline())
                .append(Doc::text("]"))
        }
    }

    fn pretty(&self) -> Doc {
        let forest = self.0;
        let mut doc = Doc::nil();
        let mut i = 0;
        let k = forest.len() - 1;
        loop {
            if i < k {
                doc = doc
                    .append(forest[i].pretty()
                            .append(Doc::text(","))
                            .append(Doc::newline()));
            }
            else if i == k {
                doc = doc
                    .append(forest[i].pretty());
                break
            }
            i += 1;
        }
        doc
    }
}

#[derive(Clone, Debug)]
pub struct Tree<'a> {
    node: String,
    forest: Forest<'a>,
}

impl<'a> Tree<'a> {
    pub fn node(node: &str) -> Tree<'a> {
        Tree {
            node: node.to_string(),
            forest: Forest::nil(),
        }
    }

    pub fn node_with_forest(node: &str, forest: &'a [Tree<'a>]) -> Tree<'a> {
        Tree {
            node: node.to_string(),
            forest: Forest::forest(forest),
        }
    }

    pub fn pretty(&self) -> Doc {
        Doc::text(self.node.clone())
            .append((self.forest).bracket())
            .group()
    }
}

#[allow(dead_code)]
pub fn main() {
    let bbbbbbs = [
        Tree::node("ccc"),
        Tree::node("dd"),
    ];
    let ffffs = [
        Tree::node("gg"),
        Tree::node("hhh"),
        Tree::node("ii"),
    ];
    let aaas = [
        Tree::node_with_forest("bbbbbb", &bbbbbbs),
        Tree::node("eee"),
        Tree::node_with_forest("ffff", &ffffs),
    ];
    let example = Tree::node_with_forest("aaaa", &aaas);

    let err_msg = "<buffer is not a utf-8 encoded string>";

    // try writing to stdout
    {
        print!("\nwriting to stdout directly:\n");
        let mut out = io::stdout();
        example
            .pretty()
            .render(70, &mut out)
    // try writing to memory
    }.and_then(|()| {
        print!("\nwriting to string then printing:\n");
        let mut mem = io::MemWriter::new();
        example
            .pretty()
            .render(70, &mut mem)
            // print to console from memory
            .map(|()| {
                let res = str::from_utf8(mem.get_ref()).unwrap_or(err_msg);
                println!("{}", res)
            })
    // print an error if anything failed
    }).unwrap_or_else(|err| {
        println!("error: {}", err)
    });
}
<|endoftext|>


<commit_before>extern crate ease;
extern crate rustc_serialize;

use std::collections::HashMap;
use ease::{Url, RestClient};

#[derive(RustcDecodable, Debug)]
struct Response {
    args: HashMap<String, String>,
    data: Option<String>,
    files: HashMap<String, String>,
    form: HashMap<String, String>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}

fn main() {
    let url = Url::parse("http://httpbin.org/post").unwrap();
    println!("{:?}",
             RestClient::new(url)
                        .post_json_as::<Response>()
        );

    let url = Url::parse("http://httpbin.org/get").unwrap();
    println!("{:?}",
             RestClient::new(url)
                        .get_json_as::<Response>()
        );
}
<commit_msg>Make example work.<commit_after>extern crate ease;
extern crate rustc_serialize;

use std::collections::HashMap;
use ease::{Url, RestClient};

#[derive(RustcDecodable, Debug)]
struct Response {
    args: HashMap<String, String>,
    data: Option<String>,
    files: Option<HashMap<String, String>>,
    form: Option<HashMap<String, String>>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}

fn main() {
    let url = Url::parse("http://httpbin.org/post").unwrap();
    println!("{:?}",
             RestClient::new(url)
                        .post_json_as::<Response>()
        );

    let url = Url::parse("http://httpbin.org/get").unwrap();
    println!("{:?}",
             RestClient::new(url)
                        .get()
        );
}
<|endoftext|>