<commit_before>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! base class automating dispatcher communication via ZMQ

use std::borrow::Cow;
use std::error::Error;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::ops::Deref;
use std::path::Path;
use std::thread;
use std::time::Duration;

use tempdir::TempDir;
use zmq::{Context, Message, Socket, SNDMORE};

/// Generic requirements for CorTeX workers
pub trait Worker: Clone + Send {
  /// Core processing method
  fn convert(&self, _: &Path) -> Result<File, Box<Error>>;
  /// Size of chunk for network communication, larger implies less IO, smaller implies less RAM use
  fn message_size(&self) -> usize;
  /// Name of the service, as registered in CorTeX
  fn get_service(&self) -> &str;
  /// URL to the CorTeX dispatcher
  fn get_source_address(&self) -> Cow<str>;
  /// URL to the CorTeX sink
  fn get_sink_address(&self) -> Cow<str>;
  /// Simultaneous threads used for one worker each
  fn pool_size(&self) -> usize {
    1
  }
  /// Sets a uniquely identifying string for this worker instance
  fn set_identity(&mut self, _identity: String) {
    unimplemented!()
  }
  /// Gets the uniquely identifying string of this worker instance
  fn get_identity(&self) -> &str {
    unimplemented!()
  }

  /// sets up the worker process, with as many threads as requested
  fn start(&mut self, limit: Option<usize>) -> Result<(), Box<Error>>
  where
    Self: 'static + Sized,
  {
    let hostname = hostname::get_hostname().unwrap_or_else(|| String::from("hostname"));
    match self.pool_size() {
      1 => {
        self.set_identity(format!("{}:engrafo:1", hostname));
        self.start_single(limit)
      }
      n => {
        let mut threads = Vec::new();
        for thread in 0..n {
          let thread_str = if thread < 10 {
            format!("0{}", thread)
          } else {
            thread.to_string()
          };
          let identity_single = format!("{}:engrafo:{}", hostname, thread_str);
          let mut thread_self: Self = self.clone();
          thread_self.set_identity(identity_single);
          threads.push(thread::spawn(move || {
            // TODO: Errors can not be shared between threads safely? What should be the robustness strategy here?
            thread_self.start_single(limit).unwrap();
          }));
        }
        for t in threads {
          t.join().unwrap();
        }
        Ok(())
      }
    }
  }
  /// main worker loop for a single thread, works in perpetuity or up to a specified `limit`
  fn start_single(&self, limit: Option<usize>) -> Result<(), Box<Error>> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let context_source = Context::new();
    let source = context_source.socket(zmq::DEALER).unwrap();
    source.set_identity(self.get_identity().as_bytes()).unwrap();

    assert!(source.connect(&self.get_source_address()).is_ok());
    // Connect to a task sink
    let context_sink = Context::new();
    let sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.get_sink_address()).is_ok());
    // Work in perpetuity
    loop {
      // Prepare a File for the input
      let input_tmpdir = TempDir::new("cortex_task").unwrap();
      let (file_result, input_filepath, input_size, taskid) =
        self.receive_from_cortex(&input_tmpdir, &source);
      let converted_result = if file_result.is_ok() {
        self.convert(Path::new(&input_filepath))
      } else {
        file_result
      };

      self.respond_to_cortex(converted_result, input_size, &taskid, &sink);

      input_tmpdir.close().unwrap();
      work_counter += 1;
      if let Some(upper_bound) = limit {
        if work_counter >= upper_bound {
          // Give enough time to complete the Final job.
          thread::sleep(Duration::new(1, 0));
          break;
        }
      }
    }
    Ok(())
  }

  /// Receive from the source endpoint
  fn receive_from_cortex(
    &self,
    input_tmpdir: &TempDir,
    source: &Socket,
  ) -> (Result<File, Box<Error>>, String, usize, String) {
    let mut taskid_msg = Message::new();
    let mut recv_msg = Message::new();
    source.send(&self.get_service(), 0).unwrap();
    source.recv(&mut taskid_msg, 0).unwrap();
    let taskid = taskid_msg.as_str().unwrap();

    let input_filepath = input_tmpdir.path().to_str().unwrap().to_string() + "/" + taskid + ".zip";

    let mut file = File::create(input_filepath.clone()).unwrap();
    let mut input_size = 0;
    loop {
      source.recv(&mut recv_msg, 0).unwrap();

      if let Ok(written) = file.write(recv_msg.deref()) {
        input_size += written;
      }
      if !source.get_rcvmore().unwrap() {
        break;
      }
    }

    let file_result = if input_size > 0 {
      file.seek(SeekFrom::Start(0)).unwrap();
      Ok(file)
    } else {
      Err(From::from("Input was empty.")) // No input, no conversion needed
    };

    info!(
      target: &format!("{}:received", self.get_identity()),
      "task {}, read {} bytes from CorTeX.", taskid, input_size
    );
    (file_result, input_filepath, input_size, taskid.to_string())
  }

  /// Respond to the sink endpoint
  fn respond_to_cortex(
    &self,
    file_result: Result<File, Box<Error>>,
    input_size: usize,
    taskid: &str,
    sink: &Socket,
  ) {
    sink.send(self.get_identity(), SNDMORE).unwrap();
    sink.send(self.get_service(), SNDMORE).unwrap();
    sink.send(taskid, SNDMORE).unwrap();
    match file_result {
      Ok(mut converted_file) => {
        let mut total_size = 0;
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          total_size += size;
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data, 0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data, SNDMORE).unwrap();
          }
        }
        info!(
          target: &format!("{}:completed", self.get_identity()),
          " task {}, sent {} bytes back to CorTeX.", taskid, total_size
        );
      }
      Err(e) => {
        // Send an empty reply, so that cortex knows this is an aberrant task
        sink.send(&Vec::new(), 0).unwrap();
        // If there was nothing to do
        // throttle in case there is a temporary local issue, such as running out of available RAM, etc.
        // but also to protect the server from DDoS-like behavior where we send broken requests at nauseam.
        if input_size == 0 {
          info!(
            target: &format!("{}:result", self.get_identity()),
            "Empty input. Throttling for a minute."
          );
        } else {
          info!(
            target: &format!("{}:result", self.get_identity()),
            "Conversion came back empty: {:?}. Throttling for a minute.", e
          );
        }
        thread::sleep(Duration::new(60, 0));
      }
    }
  }
}

mod echo;
pub use echo::EchoWorker;

mod tex_to_html;
pub use tex_to_html::TexToHtmlWorker;

#[cfg(feature = "engrafo")]
mod engrafo;
#[cfg(feature = "engrafo")]
pub use engrafo::EngrafoWorker;
<commit_msg>identity from 01, not 00<commit_after>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! base class automating dispatcher communication via ZMQ

use std::borrow::Cow;
use std::error::Error;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::ops::Deref;
use std::path::Path;
use std::thread;
use std::time::Duration;

use tempdir::TempDir;
use zmq::{Context, Message, Socket, SNDMORE};

/// Generic requirements for CorTeX workers
pub trait Worker: Clone + Send {
  /// Core processing method
  fn convert(&self, _: &Path) -> Result<File, Box<Error>>;
  /// Size of chunk for network communication, larger implies less IO, smaller implies less RAM use
  fn message_size(&self) -> usize;
  /// Name of the service, as registered in CorTeX
  fn get_service(&self) -> &str;
  /// URL to the CorTeX dispatcher
  fn get_source_address(&self) -> Cow<str>;
  /// URL to the CorTeX sink
  fn get_sink_address(&self) -> Cow<str>;
  /// Simultaneous threads used for one worker each
  fn pool_size(&self) -> usize {
    1
  }
  /// Sets a uniquely identifying string for this worker instance
  fn set_identity(&mut self, _identity: String) {
    unimplemented!()
  }
  /// Gets the uniquely identifying string of this worker instance
  fn get_identity(&self) -> &str {
    unimplemented!()
  }

  /// sets up the worker process, with as many threads as requested
  fn start(&mut self, limit: Option<usize>) -> Result<(), Box<Error>>
  where
    Self: 'static + Sized,
  {
    let hostname = hostname::get_hostname().unwrap_or_else(|| String::from("hostname"));
    match self.pool_size() {
      1 => {
        self.set_identity(format!("{}:engrafo:1", hostname));
        self.start_single(limit)
      }
      n => {
        let mut threads = Vec::new();
        for thread in 1..=n {
          let thread_str = if thread < 10 {
            format!("0{}", thread)
          } else {
            thread.to_string()
          };
          let identity_single = format!("{}:engrafo:{}", hostname, thread_str);
          let mut thread_self: Self = self.clone();
          thread_self.set_identity(identity_single);
          threads.push(thread::spawn(move || {
            // TODO: Errors can not be shared between threads safely? What should be the robustness strategy here?
            thread_self.start_single(limit).unwrap();
          }));
        }
        for t in threads {
          t.join().unwrap();
        }
        Ok(())
      }
    }
  }
  /// main worker loop for a single thread, works in perpetuity or up to a specified `limit`
  fn start_single(&self, limit: Option<usize>) -> Result<(), Box<Error>> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let context_source = Context::new();
    let source = context_source.socket(zmq::DEALER).unwrap();
    source.set_identity(self.get_identity().as_bytes()).unwrap();

    assert!(source.connect(&self.get_source_address()).is_ok());
    // Connect to a task sink
    let context_sink = Context::new();
    let sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.get_sink_address()).is_ok());
    // Work in perpetuity
    loop {
      // Prepare a File for the input
      let input_tmpdir = TempDir::new("cortex_task").unwrap();
      let (file_result, input_filepath, input_size, taskid) =
        self.receive_from_cortex(&input_tmpdir, &source);
      let converted_result = if file_result.is_ok() {
        self.convert(Path::new(&input_filepath))
      } else {
        file_result
      };

      self.respond_to_cortex(converted_result, input_size, &taskid, &sink);

      input_tmpdir.close().unwrap();
      work_counter += 1;
      if let Some(upper_bound) = limit {
        if work_counter >= upper_bound {
          // Give enough time to complete the Final job.
          thread::sleep(Duration::new(1, 0));
          break;
        }
      }
    }
    Ok(())
  }

  /// Receive from the source endpoint
  fn receive_from_cortex(
    &self,
    input_tmpdir: &TempDir,
    source: &Socket,
  ) -> (Result<File, Box<Error>>, String, usize, String) {
    let mut taskid_msg = Message::new();
    let mut recv_msg = Message::new();
    source.send(&self.get_service(), 0).unwrap();
    source.recv(&mut taskid_msg, 0).unwrap();
    let taskid = taskid_msg.as_str().unwrap();

    let input_filepath = input_tmpdir.path().to_str().unwrap().to_string() + "/" + taskid + ".zip";

    let mut file = File::create(input_filepath.clone()).unwrap();
    let mut input_size = 0;
    loop {
      source.recv(&mut recv_msg, 0).unwrap();

      if let Ok(written) = file.write(recv_msg.deref()) {
        input_size += written;
      }
      if !source.get_rcvmore().unwrap() {
        break;
      }
    }

    let file_result = if input_size > 0 {
      file.seek(SeekFrom::Start(0)).unwrap();
      Ok(file)
    } else {
      Err(From::from("Input was empty.")) // No input, no conversion needed
    };

    info!(
      target: &format!("{}:received", self.get_identity()),
      "task {}, read {} bytes from CorTeX.", taskid, input_size
    );
    (file_result, input_filepath, input_size, taskid.to_string())
  }

  /// Respond to the sink endpoint
  fn respond_to_cortex(
    &self,
    file_result: Result<File, Box<Error>>,
    input_size: usize,
    taskid: &str,
    sink: &Socket,
  ) {
    sink.send(self.get_identity(), SNDMORE).unwrap();
    sink.send(self.get_service(), SNDMORE).unwrap();
    sink.send(taskid, SNDMORE).unwrap();
    match file_result {
      Ok(mut converted_file) => {
        let mut total_size = 0;
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          total_size += size;
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data, 0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data, SNDMORE).unwrap();
          }
        }
        info!(
          target: &format!("{}:completed", self.get_identity()),
          " task {}, sent {} bytes back to CorTeX.", taskid, total_size
        );
      }
      Err(e) => {
        // Send an empty reply, so that cortex knows this is an aberrant task
        sink.send(&Vec::new(), 0).unwrap();
        // If there was nothing to do
        // throttle in case there is a temporary local issue, such as running out of available RAM, etc.
        // but also to protect the server from DDoS-like behavior where we send broken requests at nauseam.
        if input_size == 0 {
          info!(
            target: &format!("{}:result", self.get_identity()),
            "Empty input. Throttling for a minute."
          );
        } else {
          info!(
            target: &format!("{}:result", self.get_identity()),
            "Conversion came back empty: {:?}. Throttling for a minute.", e
          );
        }
        thread::sleep(Duration::new(60, 0));
      }
    }
  }
}

mod echo;
pub use echo::EchoWorker;

mod tex_to_html;
pub use tex_to_html::TexToHtmlWorker;

#[cfg(feature = "engrafo")]
mod engrafo;
#[cfg(feature = "engrafo")]
pub use engrafo::EngrafoWorker;
<|endoftext|>


<commit_before>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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.

use glib;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;
use gst_audio;
use gst_audio::prelude::*;

use gst_plugin::object::*;
use gst_plugin::element::*;
use gst_plugin::base_transform::*;

use std::{cmp, iter, i32, u64};
use std::sync::Mutex;

use byte_slice_cast::*;

use num_traits::float::Float;
use num_traits::cast::{FromPrimitive, ToPrimitive};

const DEFAULT_MAX_DELAY: u64 = 1 * gst::SECOND;
const DEFAULT_DELAY: u64 = 500 * gst::MSECOND;
const DEFAULT_INTENSITY: f64 = 0.5;
const DEFAULT_FEEDBACK: f64 = 0.0;

#[derive(Debug, Clone, Copy)]
struct Settings {
    pub max_delay: u64,
    pub delay: u64,
    pub intensity: f64,
    pub feedback: f64,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            max_delay: DEFAULT_MAX_DELAY,
            delay: DEFAULT_DELAY,
            intensity: DEFAULT_INTENSITY,
            feedback: DEFAULT_FEEDBACK,
        }
    }
}

struct State {
    info: gst_audio::AudioInfo,
    buffer: RingBuffer,
}

struct AudioEcho {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<Option<State>>,
}

static PROPERTIES: [Property; 4] = [
    Property::UInt64(
        "max-delay",
        "Maximum Delay",
        "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
        (0, u64::MAX),
        DEFAULT_MAX_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::UInt64(
        "delay",
        "Delay",
        "Delay of the echo in nanoseconds",
        (0, u64::MAX),
        DEFAULT_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "intensity",
        "Intensity",
        "Intensity of the echo",
        (0.0, 1.0),
        DEFAULT_INTENSITY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "feedback",
        "Feedback",
        "Amount of feedback",
        (0.0, 1.0),
        DEFAULT_FEEDBACK,
        PropertyMutability::ReadWrite,
    ),
];

impl AudioEcho {
    fn new(_transform: &RsBaseTransform) -> Self {
        Self {
            cat: gst::DebugCategory::new(
                "rsaudiofx",
                gst::DebugColorFlags::empty(),
                "Rust audiofx effect",
            ),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut RsBaseTransformClass) {
        klass.set_metadata(
            "Audio echo",
            "Filter/Effect/Audio",
            "Adds an echo or reverb effect to an audio stream",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_simple(
            "audio/x-raw",
            &[
                (
                    "format",
                    &gst::List::new(&[
                        &gst_audio::AUDIO_FORMAT_F32.to_string(),
                        &gst_audio::AUDIO_FORMAT_F64.to_string(),
                    ]),
                ),
                ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("layout", &"interleaved"),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(sink_pad_template);

        klass.install_properties(&PROPERTIES);

        klass.configure(BaseTransformMode::AlwaysInPlace, false, false);
    }

    fn init(element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        let imp = Self::new(element);
        Box::new(imp)
    }

    fn process<F: Float + ToPrimitive + FromPrimitive>(data: &mut [F], state: &mut State, settings: &Settings) {
        let delay_frames = (settings.delay as usize) * (state.info.channels() as usize) * (state.info.rate() as usize) /
            (gst::SECOND as usize);

        for (i, (o, e)) in data.iter_mut().zip(state.buffer.iter(delay_frames)) {
            let inp = (*i).to_f64().unwrap();
            let out = inp + settings.intensity * e;
            *o = inp + settings.feedback * e;
            *i = FromPrimitive::from_f64(out).unwrap();
        }
    }
}

impl ObjectImpl<RsBaseTransform> for AudioEcho {
    fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.max_delay = value.get().unwrap();
            }
            Property::UInt64("delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.delay = value.get().unwrap();
            }
            Property::Double("intensity", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.intensity = value.get().unwrap();
            }
            Property::Double("feedback", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.feedback = value.get().unwrap();
            }
            _ => unimplemented!(),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let settings = self.settings.lock().unwrap();
                if self.state.lock().unwrap().is_none() {
                    Ok(settings.max_delay.to_value())
                } else {
                    Err(())
                }
            }
            Property::UInt64("delay", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.delay.to_value())
            }
            Property::Double("intensity", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.intensity.to_value())
            }
            Property::Double("feedback", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.feedback.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl<RsBaseTransform> for AudioEcho {}

impl BaseTransformImpl<RsBaseTransform> for AudioEcho {

    fn transform_ip(&self, _element: &RsBaseTransform, buf: &gst::Buffer) -> gst::FlowReturn {
        let mut settings = *self.settings.lock().unwrap();
        settings.delay = cmp::min(settings.max_delay, settings.delay);

        let mut state_guard = self.state.lock().unwrap();
        let state = match *state_guard {
            None => return gst::FlowReturn::NotNegotiated,
            Some(ref mut state) => state,
        };

        let mut map = match buf.get_mut().unwrap().map_writable() {
            None => return gst::FlowReturn::Error,
            Some(map) => map,
        };

        match state.info.format() {
            gst_audio::AUDIO_FORMAT_F64 => {
                let mut data = map.as_mut_slice().as_mut_slice_of::<f64>().unwrap();
                Self::process(data, state, &settings);
            },
            gst_audio::AUDIO_FORMAT_F32 => {
                let mut data = map.as_mut_slice().as_mut_slice_of::<f32>().unwrap();
                Self::process(data, state, &settings);
            },
            _ => return gst::FlowReturn::NotNegotiated,
        }

        gst::FlowReturn::Ok
    }

    fn set_caps(
        &self,
        _element: &RsBaseTransform,
        incaps: &gst::Caps,
        outcaps: &gst::Caps,
    ) -> bool {
        if incaps != outcaps {
            return false;
        }

        let info = match gst_audio::AudioInfo::from_caps(incaps) {
            None => return false,
            Some(info) => info,
        };

        let max_delay = self.settings.lock().unwrap().max_delay;
        let size = max_delay * (info.rate() as u64) / gst::SECOND;
        let buffer_size = size * (info.channels() as u64);

        *self.state.lock().unwrap() = Some(State {
            info: info,
            buffer: RingBuffer::new(buffer_size as usize),
        });

        true
    }

    fn stop(&self, _element: &RsBaseTransform) -> bool {
        // Drop state
        let _ = self.state.lock().unwrap().take();

        true
    }
}

struct AudioEchoStatic;

impl ImplTypeStatic<RsBaseTransform> for AudioEchoStatic {
    fn get_name(&self) -> &str {
        "AudioEcho"
    }

    fn new(&self, element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        AudioEcho::init(element)
    }

    fn class_init(&self, klass: &mut RsBaseTransformClass) {
        AudioEcho::class_init(klass);
    }
}

pub fn register(plugin: &gst::Plugin) {
    let audioecho_static = AudioEchoStatic;
    let type_ = register_type(audioecho_static);
    gst::Element::register(plugin, "rsaudioecho", 0, type_);
}

struct RingBuffer {
    buffer: Vec<f64>,
    pos: usize,
    size: usize,
}

impl RingBuffer {
    fn new(size: usize) -> Self {
        let mut buffer = Vec::with_capacity(size as usize);
        buffer.extend(iter::repeat(0.0).take(size as usize));

        Self {
            buffer: buffer,
            pos: 0,
            size: size,
        }
    }

    fn iter(&mut self, delay: usize) -> RingBufferIter {
        RingBufferIter::new(self, delay)
    }
}

struct RingBufferIter<'a> {
    buffer: &'a mut RingBuffer,
    ptr: *mut f64,
    read_pos: usize,
    write_pos: usize,
}

impl<'a> RingBufferIter<'a> {
    fn new(buffer: &'a mut RingBuffer, delay: usize) -> RingBufferIter<'a> {
        assert!(buffer.size >= delay);
        assert_ne!(buffer.size, 0);

        let ptr = buffer.buffer.as_mut_ptr();

        let read_pos = (buffer.size - delay + buffer.pos) % buffer.size;
        let write_pos = buffer.pos % buffer.size;

        RingBufferIter {
            buffer: buffer,
            ptr: ptr,
            read_pos: read_pos,
            write_pos: write_pos,
        }
    }
}

impl<'a> Iterator for RingBufferIter<'a> {
    type Item = (&'a mut f64, f64);

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let res = (&mut *self.ptr.offset(self.write_pos as isize), *self.ptr.offset(self.read_pos as isize));
            self.write_pos = (self.write_pos + 1) % self.buffer.size;
            self.read_pos = (self.read_pos + 1) % self.buffer.size;

            Some(res)
        }
    }
}

impl<'a> Drop for RingBufferIter<'a> {
    fn drop(&mut self) {
        self.buffer.pos = self.write_pos;
    }
}
<commit_msg>Simplify audioecho code a bit<commit_after>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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.

use glib;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;
use gst_audio;
use gst_audio::prelude::*;

use gst_plugin::object::*;
use gst_plugin::element::*;
use gst_plugin::base_transform::*;

use std::{cmp, iter, i32, u64};
use std::sync::Mutex;

use byte_slice_cast::*;

use num_traits::float::Float;
use num_traits::cast::{FromPrimitive, ToPrimitive};

const DEFAULT_MAX_DELAY: u64 = 1 * gst::SECOND;
const DEFAULT_DELAY: u64 = 500 * gst::MSECOND;
const DEFAULT_INTENSITY: f64 = 0.5;
const DEFAULT_FEEDBACK: f64 = 0.0;

#[derive(Debug, Clone, Copy)]
struct Settings {
    pub max_delay: u64,
    pub delay: u64,
    pub intensity: f64,
    pub feedback: f64,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            max_delay: DEFAULT_MAX_DELAY,
            delay: DEFAULT_DELAY,
            intensity: DEFAULT_INTENSITY,
            feedback: DEFAULT_FEEDBACK,
        }
    }
}

struct State {
    info: gst_audio::AudioInfo,
    buffer: RingBuffer,
}

struct AudioEcho {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<Option<State>>,
}

static PROPERTIES: [Property; 4] = [
    Property::UInt64(
        "max-delay",
        "Maximum Delay",
        "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
        (0, u64::MAX),
        DEFAULT_MAX_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::UInt64(
        "delay",
        "Delay",
        "Delay of the echo in nanoseconds",
        (0, u64::MAX),
        DEFAULT_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "intensity",
        "Intensity",
        "Intensity of the echo",
        (0.0, 1.0),
        DEFAULT_INTENSITY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "feedback",
        "Feedback",
        "Amount of feedback",
        (0.0, 1.0),
        DEFAULT_FEEDBACK,
        PropertyMutability::ReadWrite,
    ),
];

impl AudioEcho {
    fn new(_transform: &RsBaseTransform) -> Self {
        Self {
            cat: gst::DebugCategory::new(
                "rsaudiofx",
                gst::DebugColorFlags::empty(),
                "Rust audiofx effect",
            ),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut RsBaseTransformClass) {
        klass.set_metadata(
            "Audio echo",
            "Filter/Effect/Audio",
            "Adds an echo or reverb effect to an audio stream",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_simple(
            "audio/x-raw",
            &[
                (
                    "format",
                    &gst::List::new(&[
                        &gst_audio::AUDIO_FORMAT_F32.to_string(),
                        &gst_audio::AUDIO_FORMAT_F64.to_string(),
                    ]),
                ),
                ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("layout", &"interleaved"),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(sink_pad_template);

        klass.install_properties(&PROPERTIES);

        klass.configure(BaseTransformMode::AlwaysInPlace, false, false);
    }

    fn init(element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        let imp = Self::new(element);
        Box::new(imp)
    }

    fn process<F: Float + ToPrimitive + FromPrimitive>(data: &mut [F], state: &mut State, settings: &Settings) {
        let delay_frames = (settings.delay as usize) * (state.info.channels() as usize) * (state.info.rate() as usize) /
            (gst::SECOND as usize);

        for (i, (o, e)) in data.iter_mut().zip(state.buffer.iter(delay_frames)) {
            let inp = (*i).to_f64().unwrap();
            let out = inp + settings.intensity * e;
            *o = inp + settings.feedback * e;
            *i = FromPrimitive::from_f64(out).unwrap();
        }
    }
}

impl ObjectImpl<RsBaseTransform> for AudioEcho {
    fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.max_delay = value.get().unwrap();
            }
            Property::UInt64("delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.delay = value.get().unwrap();
            }
            Property::Double("intensity", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.intensity = value.get().unwrap();
            }
            Property::Double("feedback", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.feedback = value.get().unwrap();
            }
            _ => unimplemented!(),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let settings = self.settings.lock().unwrap();
                if self.state.lock().unwrap().is_none() {
                    Ok(settings.max_delay.to_value())
                } else {
                    Err(())
                }
            }
            Property::UInt64("delay", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.delay.to_value())
            }
            Property::Double("intensity", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.intensity.to_value())
            }
            Property::Double("feedback", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.feedback.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl<RsBaseTransform> for AudioEcho {}

impl BaseTransformImpl<RsBaseTransform> for AudioEcho {

    fn transform_ip(&self, _element: &RsBaseTransform, buf: &gst::Buffer) -> gst::FlowReturn {
        let mut settings = *self.settings.lock().unwrap();
        settings.delay = cmp::min(settings.max_delay, settings.delay);

        let mut state_guard = self.state.lock().unwrap();
        let state = match *state_guard {
            None => return gst::FlowReturn::NotNegotiated,
            Some(ref mut state) => state,
        };

        let mut map = match buf.get_mut().and_then(|b| b.map_writable()) {
            None => return gst::FlowReturn::Error,
            Some(map) => map,
        };

        match state.info.format() {
            gst_audio::AUDIO_FORMAT_F64 => {
                let mut data = map.as_mut_slice().as_mut_slice_of::<f64>().unwrap();
                Self::process(data, state, &settings);
            },
            gst_audio::AUDIO_FORMAT_F32 => {
                let mut data = map.as_mut_slice().as_mut_slice_of::<f32>().unwrap();
                Self::process(data, state, &settings);
            },
            _ => return gst::FlowReturn::NotNegotiated,
        }

        gst::FlowReturn::Ok
    }

    fn set_caps(
        &self,
        _element: &RsBaseTransform,
        incaps: &gst::Caps,
        outcaps: &gst::Caps,
    ) -> bool {
        if incaps != outcaps {
            return false;
        }

        let info = match gst_audio::AudioInfo::from_caps(incaps) {
            None => return false,
            Some(info) => info,
        };

        let max_delay = self.settings.lock().unwrap().max_delay;
        let size = max_delay * (info.rate() as u64) / gst::SECOND;
        let buffer_size = size * (info.channels() as u64);

        *self.state.lock().unwrap() = Some(State {
            info: info,
            buffer: RingBuffer::new(buffer_size as usize),
        });

        true
    }

    fn stop(&self, _element: &RsBaseTransform) -> bool {
        // Drop state
        let _ = self.state.lock().unwrap().take();

        true
    }
}

struct AudioEchoStatic;

impl ImplTypeStatic<RsBaseTransform> for AudioEchoStatic {
    fn get_name(&self) -> &str {
        "AudioEcho"
    }

    fn new(&self, element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        AudioEcho::init(element)
    }

    fn class_init(&self, klass: &mut RsBaseTransformClass) {
        AudioEcho::class_init(klass);
    }
}

pub fn register(plugin: &gst::Plugin) {
    let audioecho_static = AudioEchoStatic;
    let type_ = register_type(audioecho_static);
    gst::Element::register(plugin, "rsaudioecho", 0, type_);
}

struct RingBuffer {
    buffer: Box<[f64]>,
    pos: usize,
}

impl RingBuffer {
    fn new(size: usize) -> Self {
        let mut buffer = Vec::with_capacity(size as usize);
        buffer.extend(iter::repeat(0.0).take(size as usize));

        Self {
            buffer: buffer.into_boxed_slice(),
            pos: 0,
        }
    }

    fn iter(&mut self, delay: usize) -> RingBufferIter {
        RingBufferIter::new(self, delay)
    }
}

struct RingBufferIter<'a> {
    buffer: &'a mut RingBuffer,
    read_pos: usize,
    write_pos: usize,
    size: usize,
}

impl<'a> RingBufferIter<'a> {
    fn new(buffer: &'a mut RingBuffer, delay: usize) -> RingBufferIter<'a> {
        let size = buffer.buffer.len();

        assert!(size >= delay);
        assert_ne!(size, 0);

        let read_pos = (size - delay + buffer.pos) % size;
        let write_pos = buffer.pos % size;

        RingBufferIter {
            buffer: buffer,
            read_pos: read_pos,
            write_pos: write_pos,
            size: size,
        }
    }
}

impl<'a> Iterator for RingBufferIter<'a> {
    type Item = (&'a mut f64, f64);

    fn next(&mut self) -> Option<Self::Item> {
        let res = unsafe {
            let r = *self.buffer.buffer.get_unchecked(self.read_pos);
            let w = self.buffer.buffer.get_unchecked_mut(self.write_pos);
            // Cast needed to get from &mut f64 to &'a mut f64
            (&mut *(w as *mut f64), r)
        };

        self.write_pos = (self.write_pos + 1) % self.size;
        self.read_pos = (self.read_pos + 1) % self.size;

        Some(res)
    }
}

impl<'a> Drop for RingBufferIter<'a> {
    fn drop(&mut self) {
        self.buffer.pos = self.write_pos;
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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.

use glib;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;
use gst_audio;
use gst_audio::prelude::*;

use gst_plugin::object::*;
use gst_plugin::element::*;
use gst_plugin::base_transform::*;

use std::{cmp, iter, i32, u64};
use std::sync::Mutex;

use byte_slice_cast::*;

use num_traits::float::Float;
use num_traits::cast::{FromPrimitive, ToPrimitive};

const DEFAULT_MAX_DELAY: u64 = 1 * gst::SECOND;
const DEFAULT_DELAY: u64 = 500 * gst::MSECOND;
const DEFAULT_INTENSITY: f64 = 0.5;
const DEFAULT_FEEDBACK: f64 = 0.0;

#[derive(Debug, Clone, Copy)]
struct Settings {
    pub max_delay: u64,
    pub delay: u64,
    pub intensity: f64,
    pub feedback: f64,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            max_delay: DEFAULT_MAX_DELAY,
            delay: DEFAULT_DELAY,
            intensity: DEFAULT_INTENSITY,
            feedback: DEFAULT_FEEDBACK,
        }
    }
}

struct State {
    info: gst_audio::AudioInfo,
    buffer: RingBuffer,
}

struct AudioEcho {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<Option<State>>,
}

static PROPERTIES: [Property; 4] = [
    Property::UInt64(
        "max-delay",
        "Maximum Delay",
        "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
        (0, u64::MAX),
        DEFAULT_MAX_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::UInt64(
        "delay",
        "Delay",
        "Delay of the echo in nanoseconds",
        (0, u64::MAX),
        DEFAULT_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "intensity",
        "Intensity",
        "Intensity of the echo",
        (0.0, 1.0),
        DEFAULT_INTENSITY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "feedback",
        "Feedback",
        "Amount of feedback",
        (0.0, 1.0),
        DEFAULT_FEEDBACK,
        PropertyMutability::ReadWrite,
    ),
];

impl AudioEcho {
    fn new(_transform: &RsBaseTransform) -> Self {
        Self {
            cat: gst::DebugCategory::new(
                "rsaudiofx",
                gst::DebugColorFlags::empty(),
                "Rust audiofx effect",
            ),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut RsBaseTransformClass) {
        klass.set_metadata(
            "Audio echo",
            "Filter/Effect/Audio",
            "Adds an echo or reverb effect to an audio stream",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_simple(
            "audio/x-raw",
            &[
                (
                    "format",
                    &gst::List::new(&[
                        &gst_audio::AUDIO_FORMAT_F32.to_string(),
                        &gst_audio::AUDIO_FORMAT_F64.to_string(),
                    ]),
                ),
                ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("layout", &"interleaved"),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(sink_pad_template);

        klass.install_properties(&PROPERTIES);

        klass.configure(BaseTransformMode::AlwaysInPlace, false, false);
    }

    fn init(element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        let imp = Self::new(element);
        Box::new(imp)
    }

    fn process<F: Float + ToPrimitive + FromPrimitive>(
        data: &mut [F],
        state: &mut State,
        settings: &Settings,
    ) {
        let delay_frames = (settings.delay as usize) * (state.info.channels() as usize)
            * (state.info.rate() as usize) / (gst::SECOND as usize);

        for (i, (o, e)) in data.iter_mut().zip(state.buffer.iter(delay_frames)) {
            let inp = (*i).to_f64().unwrap();
            let out = inp + settings.intensity * e;
            *o = inp + settings.feedback * e;
            *i = FromPrimitive::from_f64(out).unwrap();
        }
    }
}

impl ObjectImpl<RsBaseTransform> for AudioEcho {
    fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.max_delay = value.get().unwrap();
            }
            Property::UInt64("delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.delay = value.get().unwrap();
            }
            Property::Double("intensity", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.intensity = value.get().unwrap();
            }
            Property::Double("feedback", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.feedback = value.get().unwrap();
            }
            _ => unimplemented!(),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let settings = self.settings.lock().unwrap();
                if self.state.lock().unwrap().is_none() {
                    Ok(settings.max_delay.to_value())
                } else {
                    Err(())
                }
            }
            Property::UInt64("delay", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.delay.to_value())
            }
            Property::Double("intensity", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.intensity.to_value())
            }
            Property::Double("feedback", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.feedback.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl<RsBaseTransform> for AudioEcho {}

impl BaseTransformImpl<RsBaseTransform> for AudioEcho {
    fn transform_ip(
        &self,
        _element: &RsBaseTransform,
        buf: &mut gst::BufferRef,
    ) -> gst::FlowReturn {
        let mut settings = *self.settings.lock().unwrap();
        settings.delay = cmp::min(settings.max_delay, settings.delay);

        let mut state_guard = self.state.lock().unwrap();
        let state = match *state_guard {
            None => return gst::FlowReturn::NotNegotiated,
            Some(ref mut state) => state,
        };

        let mut map = match buf.map_writable() {
            None => return gst::FlowReturn::Error,
            Some(map) => map,
        };

        match state.info.format() {
            gst_audio::AUDIO_FORMAT_F64 => {
                let mut data = map.as_mut_slice().as_mut_slice_of::<f64>().unwrap();
                Self::process(data, state, &settings);
            }
            gst_audio::AUDIO_FORMAT_F32 => {
                let mut data = map.as_mut_slice().as_mut_slice_of::<f32>().unwrap();
                Self::process(data, state, &settings);
            }
            _ => return gst::FlowReturn::NotNegotiated,
        }

        gst::FlowReturn::Ok
    }

    fn set_caps(
        &self,
        _element: &RsBaseTransform,
        incaps: &gst::Caps,
        outcaps: &gst::Caps,
    ) -> bool {
        if incaps != outcaps {
            return false;
        }

        let info = match gst_audio::AudioInfo::from_caps(incaps) {
            None => return false,
            Some(info) => info,
        };

        let max_delay = self.settings.lock().unwrap().max_delay;
        let size = max_delay * (info.rate() as u64) / gst::SECOND;
        let buffer_size = size * (info.channels() as u64);

        *self.state.lock().unwrap() = Some(State {
            info: info,
            buffer: RingBuffer::new(buffer_size as usize),
        });

        true
    }

    fn stop(&self, _element: &RsBaseTransform) -> bool {
        // Drop state
        let _ = self.state.lock().unwrap().take();

        true
    }
}

struct AudioEchoStatic;

impl ImplTypeStatic<RsBaseTransform> for AudioEchoStatic {
    fn get_name(&self) -> &str {
        "AudioEcho"
    }

    fn new(&self, element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        AudioEcho::init(element)
    }

    fn class_init(&self, klass: &mut RsBaseTransformClass) {
        AudioEcho::class_init(klass);
    }
}

pub fn register(plugin: &gst::Plugin) {
    let audioecho_static = AudioEchoStatic;
    let type_ = register_type(audioecho_static);
    gst::Element::register(plugin, "rsaudioecho", 0, type_);
}

struct RingBuffer {
    buffer: Box<[f64]>,
    pos: usize,
}

impl RingBuffer {
    fn new(size: usize) -> Self {
        let mut buffer = Vec::with_capacity(size as usize);
        buffer.extend(iter::repeat(0.0).take(size as usize));

        Self {
            buffer: buffer.into_boxed_slice(),
            pos: 0,
        }
    }

    fn iter(&mut self, delay: usize) -> RingBufferIter {
        RingBufferIter::new(self, delay)
    }
}

struct RingBufferIter<'a> {
    buffer: &'a mut [f64],
    buffer_pos: &'a mut usize,
    read_pos: usize,
    write_pos: usize,
}

impl<'a> RingBufferIter<'a> {
    fn new(buffer: &'a mut RingBuffer, delay: usize) -> RingBufferIter<'a> {
        let size = buffer.buffer.len();

        assert!(size >= delay);
        assert_ne!(size, 0);

        let read_pos = (size - delay + buffer.pos) % size;
        let write_pos = buffer.pos % size;

        let buffer_pos = &mut buffer.pos;
        let buffer = &mut buffer.buffer;

        RingBufferIter {
            buffer: buffer,
            buffer_pos: buffer_pos,
            read_pos: read_pos,
            write_pos: write_pos,
        }
    }
}

impl<'a> Iterator for RingBufferIter<'a> {
    type Item = (&'a mut f64, f64);

    fn next(&mut self) -> Option<Self::Item> {
        let res = unsafe {
            let r = *self.buffer.get_unchecked(self.read_pos);
            let w = self.buffer.get_unchecked_mut(self.write_pos);
            // Cast needed to get from &mut f64 to &'a mut f64
            (&mut *(w as *mut f64), r)
        };

        let size = self.buffer.len();
        self.write_pos = (self.write_pos + 1) % size;
        self.read_pos = (self.read_pos + 1) % size;

        Some(res)
    }
}

impl<'a> Drop for RingBufferIter<'a> {
    fn drop(&mut self) {
        *self.buffer_pos = self.write_pos;
    }
}
<commit_msg>audioecho: Don't unnecessarily mark variable as mutable<commit_after>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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.

use glib;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;
use gst_audio;
use gst_audio::prelude::*;

use gst_plugin::object::*;
use gst_plugin::element::*;
use gst_plugin::base_transform::*;

use std::{cmp, iter, i32, u64};
use std::sync::Mutex;

use byte_slice_cast::*;

use num_traits::float::Float;
use num_traits::cast::{FromPrimitive, ToPrimitive};

const DEFAULT_MAX_DELAY: u64 = 1 * gst::SECOND;
const DEFAULT_DELAY: u64 = 500 * gst::MSECOND;
const DEFAULT_INTENSITY: f64 = 0.5;
const DEFAULT_FEEDBACK: f64 = 0.0;

#[derive(Debug, Clone, Copy)]
struct Settings {
    pub max_delay: u64,
    pub delay: u64,
    pub intensity: f64,
    pub feedback: f64,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            max_delay: DEFAULT_MAX_DELAY,
            delay: DEFAULT_DELAY,
            intensity: DEFAULT_INTENSITY,
            feedback: DEFAULT_FEEDBACK,
        }
    }
}

struct State {
    info: gst_audio::AudioInfo,
    buffer: RingBuffer,
}

struct AudioEcho {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<Option<State>>,
}

static PROPERTIES: [Property; 4] = [
    Property::UInt64(
        "max-delay",
        "Maximum Delay",
        "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
        (0, u64::MAX),
        DEFAULT_MAX_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::UInt64(
        "delay",
        "Delay",
        "Delay of the echo in nanoseconds",
        (0, u64::MAX),
        DEFAULT_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "intensity",
        "Intensity",
        "Intensity of the echo",
        (0.0, 1.0),
        DEFAULT_INTENSITY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "feedback",
        "Feedback",
        "Amount of feedback",
        (0.0, 1.0),
        DEFAULT_FEEDBACK,
        PropertyMutability::ReadWrite,
    ),
];

impl AudioEcho {
    fn new(_transform: &RsBaseTransform) -> Self {
        Self {
            cat: gst::DebugCategory::new(
                "rsaudiofx",
                gst::DebugColorFlags::empty(),
                "Rust audiofx effect",
            ),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut RsBaseTransformClass) {
        klass.set_metadata(
            "Audio echo",
            "Filter/Effect/Audio",
            "Adds an echo or reverb effect to an audio stream",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_simple(
            "audio/x-raw",
            &[
                (
                    "format",
                    &gst::List::new(&[
                        &gst_audio::AUDIO_FORMAT_F32.to_string(),
                        &gst_audio::AUDIO_FORMAT_F64.to_string(),
                    ]),
                ),
                ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("layout", &"interleaved"),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(sink_pad_template);

        klass.install_properties(&PROPERTIES);

        klass.configure(BaseTransformMode::AlwaysInPlace, false, false);
    }

    fn init(element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        let imp = Self::new(element);
        Box::new(imp)
    }

    fn process<F: Float + ToPrimitive + FromPrimitive>(
        data: &mut [F],
        state: &mut State,
        settings: &Settings,
    ) {
        let delay_frames = (settings.delay as usize) * (state.info.channels() as usize)
            * (state.info.rate() as usize) / (gst::SECOND as usize);

        for (i, (o, e)) in data.iter_mut().zip(state.buffer.iter(delay_frames)) {
            let inp = (*i).to_f64().unwrap();
            let out = inp + settings.intensity * e;
            *o = inp + settings.feedback * e;
            *i = FromPrimitive::from_f64(out).unwrap();
        }
    }
}

impl ObjectImpl<RsBaseTransform> for AudioEcho {
    fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.max_delay = value.get().unwrap();
            }
            Property::UInt64("delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.delay = value.get().unwrap();
            }
            Property::Double("intensity", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.intensity = value.get().unwrap();
            }
            Property::Double("feedback", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.feedback = value.get().unwrap();
            }
            _ => unimplemented!(),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let settings = self.settings.lock().unwrap();
                if self.state.lock().unwrap().is_none() {
                    Ok(settings.max_delay.to_value())
                } else {
                    Err(())
                }
            }
            Property::UInt64("delay", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.delay.to_value())
            }
            Property::Double("intensity", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.intensity.to_value())
            }
            Property::Double("feedback", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.feedback.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl<RsBaseTransform> for AudioEcho {}

impl BaseTransformImpl<RsBaseTransform> for AudioEcho {
    fn transform_ip(
        &self,
        _element: &RsBaseTransform,
        buf: &mut gst::BufferRef,
    ) -> gst::FlowReturn {
        let mut settings = *self.settings.lock().unwrap();
        settings.delay = cmp::min(settings.max_delay, settings.delay);

        let mut state_guard = self.state.lock().unwrap();
        let state = match *state_guard {
            None => return gst::FlowReturn::NotNegotiated,
            Some(ref mut state) => state,
        };

        let mut map = match buf.map_writable() {
            None => return gst::FlowReturn::Error,
            Some(map) => map,
        };

        match state.info.format() {
            gst_audio::AUDIO_FORMAT_F64 => {
                let data = map.as_mut_slice().as_mut_slice_of::<f64>().unwrap();
                Self::process(data, state, &settings);
            }
            gst_audio::AUDIO_FORMAT_F32 => {
                let data = map.as_mut_slice().as_mut_slice_of::<f32>().unwrap();
                Self::process(data, state, &settings);
            }
            _ => return gst::FlowReturn::NotNegotiated,
        }

        gst::FlowReturn::Ok
    }

    fn set_caps(
        &self,
        _element: &RsBaseTransform,
        incaps: &gst::Caps,
        outcaps: &gst::Caps,
    ) -> bool {
        if incaps != outcaps {
            return false;
        }

        let info = match gst_audio::AudioInfo::from_caps(incaps) {
            None => return false,
            Some(info) => info,
        };

        let max_delay = self.settings.lock().unwrap().max_delay;
        let size = max_delay * (info.rate() as u64) / gst::SECOND;
        let buffer_size = size * (info.channels() as u64);

        *self.state.lock().unwrap() = Some(State {
            info: info,
            buffer: RingBuffer::new(buffer_size as usize),
        });

        true
    }

    fn stop(&self, _element: &RsBaseTransform) -> bool {
        // Drop state
        let _ = self.state.lock().unwrap().take();

        true
    }
}

struct AudioEchoStatic;

impl ImplTypeStatic<RsBaseTransform> for AudioEchoStatic {
    fn get_name(&self) -> &str {
        "AudioEcho"
    }

    fn new(&self, element: &RsBaseTransform) -> Box<BaseTransformImpl<RsBaseTransform>> {
        AudioEcho::init(element)
    }

    fn class_init(&self, klass: &mut RsBaseTransformClass) {
        AudioEcho::class_init(klass);
    }
}

pub fn register(plugin: &gst::Plugin) {
    let audioecho_static = AudioEchoStatic;
    let type_ = register_type(audioecho_static);
    gst::Element::register(plugin, "rsaudioecho", 0, type_);
}

struct RingBuffer {
    buffer: Box<[f64]>,
    pos: usize,
}

impl RingBuffer {
    fn new(size: usize) -> Self {
        let mut buffer = Vec::with_capacity(size as usize);
        buffer.extend(iter::repeat(0.0).take(size as usize));

        Self {
            buffer: buffer.into_boxed_slice(),
            pos: 0,
        }
    }

    fn iter(&mut self, delay: usize) -> RingBufferIter {
        RingBufferIter::new(self, delay)
    }
}

struct RingBufferIter<'a> {
    buffer: &'a mut [f64],
    buffer_pos: &'a mut usize,
    read_pos: usize,
    write_pos: usize,
}

impl<'a> RingBufferIter<'a> {
    fn new(buffer: &'a mut RingBuffer, delay: usize) -> RingBufferIter<'a> {
        let size = buffer.buffer.len();

        assert!(size >= delay);
        assert_ne!(size, 0);

        let read_pos = (size - delay + buffer.pos) % size;
        let write_pos = buffer.pos % size;

        let buffer_pos = &mut buffer.pos;
        let buffer = &mut buffer.buffer;

        RingBufferIter {
            buffer: buffer,
            buffer_pos: buffer_pos,
            read_pos: read_pos,
            write_pos: write_pos,
        }
    }
}

impl<'a> Iterator for RingBufferIter<'a> {
    type Item = (&'a mut f64, f64);

    fn next(&mut self) -> Option<Self::Item> {
        let res = unsafe {
            let r = *self.buffer.get_unchecked(self.read_pos);
            let w = self.buffer.get_unchecked_mut(self.write_pos);
            // Cast needed to get from &mut f64 to &'a mut f64
            (&mut *(w as *mut f64), r)
        };

        let size = self.buffer.len();
        self.write_pos = (self.write_pos + 1) % size;
        self.read_pos = (self.read_pos + 1) % size;

        Some(res)
    }
}

impl<'a> Drop for RingBufferIter<'a> {
    fn drop(&mut self) {
        *self.buffer_pos = self.write_pos;
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::marker::PhantomFn;
use std::str;
use libc::{c_char, c_void};

use block::Block;
use runtime::{Class, Object, Sel};

#[cfg(target_pointer_width = "64")]
const CODE_INLINE_CAP: usize = 30;

#[cfg(target_pointer_width = "32")]
const CODE_INLINE_CAP: usize = 14;

enum Code {
    Slice(&'static str),
    Owned(String),
    Inline(u8, [u8; CODE_INLINE_CAP]),
}

/// An Objective-C type encoding.
///
/// For more information, see Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub struct Encoding {
    code: Code,
}

impl Encoding {
    /// Returns self as a `str`.
    pub fn as_str(&self) -> &str {
        match self.code {
            Code::Slice(code) => code,
            Code::Owned(ref code) => code,
            Code::Inline(len, ref bytes) => unsafe {
                str::from_utf8_unchecked(&bytes[..len as usize])
            }
        }
    }
}

impl Clone for Encoding {
    fn clone(&self) -> Encoding {
        let code = match self.code {
            Code::Slice(code) => Code::Slice(code),
            Code::Owned(ref code) => Code::Owned(code.clone()),
            Code::Inline(len, bytes) => Code::Inline(len, bytes),
        };
        Encoding { code: code }
    }
}

impl PartialEq for Encoding {
    fn eq(&self, other: &Encoding) -> bool {
        self.as_str() == other.as_str()
    }
}

impl fmt::Debug for Encoding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

pub fn from_static_str(code: &'static str) -> Encoding {
    Encoding { code: Code::Slice(code) }
}

/// Types that have an Objective-C type encoding.
///
/// Unsafe because Objective-C will make assumptions about the type (like its
/// size and alignment) from its encoding, so the implementer must verify that
/// the encoding is accurate.
pub unsafe trait Encode : PhantomFn<Self> {
    /// Returns the Objective-C type encoding for Self.
    fn encode() -> Encoding;
}

macro_rules! encode_impls {
    ($($t:ty : $s:expr,)*) => ($(
        unsafe impl Encode for $t {
            fn encode() -> Encoding { from_static_str($s) }
        }
    )*);
}

encode_impls!(
    i8: "c",
    i16: "s",
    i32: "i",
    i64: "q",
    u8: "C",
    u16: "S",
    u32: "I",
    u64: "Q",
    f32: "f",
    f64: "d",
    bool: "B",
    (): "v",
    *mut c_char: "*",
    *const c_char: "r*",
    *mut c_void: "^v",
    *const c_void: "r^v",
    Sel: ":",
);

unsafe impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { i32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { i64::encode() }
}

unsafe impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { u32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { u64::encode() }
}

macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        unsafe impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }
    );
}

encode_message_impl!("@", Object);

encode_message_impl!("#", Class);

encode_message_impl!("@?", Block, A, R);

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::Encode;

    #[test]
    fn test_encode() {
        assert!(u32::encode().as_str() == "I");
        assert!(<()>::encode().as_str() == "v");
        assert!(<&Object>::encode().as_str() == "@");
        assert!(<*mut Object>::encode().as_str() == "@");
        assert!(<&Class>::encode().as_str() == "#");
        assert!(Sel::encode().as_str() == ":");
    }
}
<commit_msg>Added from_str<commit_after>use std::fmt;
use std::marker::PhantomFn;
use std::str;
use libc::{c_char, c_void};

use block::Block;
use runtime::{Class, Object, Sel};

#[cfg(target_pointer_width = "64")]
const CODE_INLINE_CAP: usize = 30;

#[cfg(target_pointer_width = "32")]
const CODE_INLINE_CAP: usize = 14;

enum Code {
    Slice(&'static str),
    Owned(String),
    Inline(u8, [u8; CODE_INLINE_CAP]),
}

/// An Objective-C type encoding.
///
/// For more information, see Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub struct Encoding {
    code: Code,
}

impl Encoding {
    /// Returns self as a `str`.
    pub fn as_str(&self) -> &str {
        match self.code {
            Code::Slice(code) => code,
            Code::Owned(ref code) => code,
            Code::Inline(len, ref bytes) => unsafe {
                str::from_utf8_unchecked(&bytes[..len as usize])
            }
        }
    }
}

impl Clone for Encoding {
    fn clone(&self) -> Encoding {
        if let Code::Slice(code) = self.code {
            from_static_str(code)
        } else {
            from_str(self.as_str())
        }
    }
}

impl PartialEq for Encoding {
    fn eq(&self, other: &Encoding) -> bool {
        self.as_str() == other.as_str()
    }
}

impl fmt::Debug for Encoding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

pub fn from_static_str(code: &'static str) -> Encoding {
    Encoding { code: Code::Slice(code) }
}

pub fn from_str(code: &str) -> Encoding {
    if code.len() > CODE_INLINE_CAP {
        Encoding { code: Code::Owned(code.to_string()) }
    } else {
        let mut bytes = [0; CODE_INLINE_CAP];
        for (dst, byte) in bytes.iter_mut().zip(code.bytes()) {
            *dst = byte;
        }
        Encoding { code: Code::Inline(code.len() as u8, bytes) }
    }
}

/// Types that have an Objective-C type encoding.
///
/// Unsafe because Objective-C will make assumptions about the type (like its
/// size and alignment) from its encoding, so the implementer must verify that
/// the encoding is accurate.
pub unsafe trait Encode : PhantomFn<Self> {
    /// Returns the Objective-C type encoding for Self.
    fn encode() -> Encoding;
}

macro_rules! encode_impls {
    ($($t:ty : $s:expr,)*) => ($(
        unsafe impl Encode for $t {
            fn encode() -> Encoding { from_static_str($s) }
        }
    )*);
}

encode_impls!(
    i8: "c",
    i16: "s",
    i32: "i",
    i64: "q",
    u8: "C",
    u16: "S",
    u32: "I",
    u64: "Q",
    f32: "f",
    f64: "d",
    bool: "B",
    (): "v",
    *mut c_char: "*",
    *const c_char: "r*",
    *mut c_void: "^v",
    *const c_void: "r^v",
    Sel: ":",
);

unsafe impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { i32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { i64::encode() }
}

unsafe impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { u32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { u64::encode() }
}

macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        unsafe impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }
    );
}

encode_message_impl!("@", Object);

encode_message_impl!("#", Class);

encode_message_impl!("@?", Block, A, R);

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::Encode;

    #[test]
    fn test_encode() {
        assert!(u32::encode().as_str() == "I");
        assert!(<()>::encode().as_str() == "v");
        assert!(<&Object>::encode().as_str() == "@");
        assert!(<*mut Object>::encode().as_str() == "@");
        assert!(<&Class>::encode().as_str() == "#");
        assert!(Sel::encode().as_str() == ":");
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

// Test that we print out the names of type parameters correctly in
// our error messages.

fn foo<Foo, Bar>(x: Foo) -> Bar { x } //~ ERROR expected `Bar`, found `Foo`

fn main() {}
<commit_msg>Add a test for failure to unify type parameters<commit_after>// Copyright 2014 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.

// Test that we print out the names of type parameters correctly in
// our error messages.

fn foo<Foo, Bar>(x: Foo) -> Bar {
    x
//~^ ERROR expected `Bar`, found `Foo` (expected type parameter, found a different type parameter)
}

fn main() {}
<|endoftext|>


<commit_before>// Copyright 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.

use std::task;
use std::rand::{task_rng, Rng};

const MAX_LEN: uint = 20;
static mut drop_counts: [uint, .. MAX_LEN] = [0, .. MAX_LEN];
static mut clone_count: uint = 0;

#[deriving(Rand, PartialEq, PartialOrd, Eq, Ord)]
struct DropCounter { x: uint, clone_num: uint }

impl Clone for DropCounter {
    fn clone(&self) -> DropCounter {
        let num = unsafe { clone_count };
        unsafe { clone_count += 1; }
        DropCounter {
            x: self.x,
            clone_num: num
        }
    }
}

impl Drop for DropCounter {
    fn drop(&mut self) {
        unsafe {
            // Rand creates some with arbitrary clone_nums
            if self.clone_num < MAX_LEN {
                drop_counts[self.clone_num] += 1;
            }
        }
    }
}

pub fn main() {
    // len can't go above 64.
    for len in range(2u, MAX_LEN) {
        for _ in range(0i, 10) {
            let main = task_rng().gen_iter::<DropCounter>()
                                 .take(len)
                                 .collect::<Vec<DropCounter>>();

            // work out the total number of comparisons required to sort
            // this array...
            let mut count = 0;
            main.clone().as_mut_slice().sort_by(|a, b| { count += 1; a.cmp(b) });

            // ... and then fail on each and every single one.
            for fail_countdown in range(0i, count) {
                // refresh the counters.
                unsafe {
                    drop_counts = [0, .. MAX_LEN];
                    clone_count = 0;
                }

                let v = main.clone();

                task::try(proc() {
                        let mut v = v;
                        let mut fail_countdown = fail_countdown;
                        v.as_mut_slice().sort_by(|a, b| {
                                if fail_countdown == 0 {
                                    fail!()
                                }
                                fail_countdown -= 1;
                                a.cmp(b)
                            })
                    });

                // check that the number of things dropped is exactly
                // what we expect (i.e. the contents of `v`).
                unsafe {
                    for (i, &c) in drop_counts.iter().enumerate() {
                        let expected = if i < len {1} else {0};
                        assert!(c == expected,
                                "found drop count == {} for i == {}, len == {}",
                                c, i, len);
                    }
                }
            }
        }
    }
}
<commit_msg>test: make the sort failure-safety test unsafeless and more obvious.<commit_after>// Copyright 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.

use std::task;
use std::sync::atomics::{AtomicUint, INIT_ATOMIC_UINT, Relaxed};
use std::rand::{task_rng, Rng, Rand};

const REPEATS: uint = 5;
const MAX_LEN: uint = 32;
static drop_counts: [AtomicUint, .. MAX_LEN] =
    // FIXME #5244: AtomicUint is not Copy.
    [
        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,

        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
        INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT, INIT_ATOMIC_UINT,
     ];

static creation_count: AtomicUint = INIT_ATOMIC_UINT;

#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)]
struct DropCounter { x: uint, creation_id: uint }

impl Rand for DropCounter {
    fn rand<R: Rng>(rng: &mut R) -> DropCounter {
        // (we're not using this concurrently, so Relaxed is fine.)
        let num = creation_count.fetch_add(1, Relaxed);
        DropCounter {
            x: rng.gen(),
            creation_id: num
        }
    }
}

impl Drop for DropCounter {
    fn drop(&mut self) {
        drop_counts[self.creation_id].fetch_add(1, Relaxed);
    }
}

pub fn main() {
    assert!(MAX_LEN <= std::uint::BITS);
    // len can't go above 64.
    for len in range(2, MAX_LEN) {
        for _ in range(0, REPEATS) {
            // reset the count for these new DropCounters, so their
            // IDs start from 0.
            creation_count.store(0, Relaxed);

            let main = task_rng().gen_iter::<DropCounter>()
                                 .take(len)
                                 .collect::<Vec<DropCounter>>();

            // work out the total number of comparisons required to sort
            // this array...
            let mut count = 0;
            main.clone().as_mut_slice().sort_by(|a, b| { count += 1; a.cmp(b) });

            // ... and then fail on each and every single one.
            for fail_countdown in range(0i, count) {
                // refresh the counters.
                for c in drop_counts.iter() {
                    c.store(0, Relaxed);
                }

                let v = main.clone();

                let _ = task::try(proc() {
                        let mut v = v;
                        let mut fail_countdown = fail_countdown;
                        v.as_mut_slice().sort_by(|a, b| {
                                if fail_countdown == 0 {
                                    fail!()
                                }
                                fail_countdown -= 1;
                                a.cmp(b)
                            })
                    });

                // check that the number of things dropped is exactly
                // what we expect (i.e. the contents of `v`).
                for (i, c) in drop_counts.iter().enumerate().take(len) {
                    let count = c.load(Relaxed);
                    assert!(count == 1,
                            "found drop count == {} for i == {}, len == {}",
                            count, i, len);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::net::ToSocketAddrs;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

use futures::channel::oneshot;
use futures::future;
use futures::future::FutureExt;
use futures::future::TryFutureExt;

use httpbis;
use httpbis::for_test::*;
use httpbis::*;

use super::BIND_HOST;
use crate::assert_types::assert_send_future;
use std::thread::JoinHandle;
use tokio::runtime::Runtime;

/// Single connection HTTP/server.
/// Accepts only one connection.
pub struct ServerOneConn {
    from_loop: FromLoop,
    join_handle: Option<thread::JoinHandle<()>>,
    shutdown_tx: Option<oneshot::Sender<()>>,
    conn: Arc<Mutex<Option<ServerConn>>>,
}

struct FromLoop {
    port: u16,
}

impl ServerOneConn {
    pub fn new_fn<S>(port: u16, service: S) -> Self
    where
        S: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> httpbis::Result<()>
            + Send
            + Sync
            + 'static,
    {
        ServerOneConn::new_fn_impl(port, service)
    }

    #[allow(dead_code)]
    fn new_fn_impl<S>(port: u16, service: S) -> Self
    where
        S: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> httpbis::Result<()>
            + Send
            + Sync
            + 'static,
    {
        let (from_loop_tx, from_loop_rx) = std::sync::mpsc::channel();
        let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();

        let conn: Arc<Mutex<Option<ServerConn>>> = Default::default();

        let conn_for_thread = conn.clone();

        let join_handle: JoinHandle<()> = thread::Builder::new()
            .name("server_one_conn".to_owned())
            .spawn(move || {
                let mut lp = Runtime::new().unwrap();

                let mut listener = lp
                    .block_on(tokio::net::TcpListener::bind(
                        &(BIND_HOST, port).to_socket_addrs().unwrap().next().unwrap(),
                    ))
                    .unwrap();

                let actual_port = listener.local_addr().unwrap().port();
                from_loop_tx
                    .send(FromLoop { port: actual_port })
                    .ok()
                    .unwrap();

                let handle = lp.handle().clone();

                let conn = listener.accept().map_err(httpbis::Error::from);

                // TODO: close listening port
                //drop(listener);

                let future = conn.and_then(move |(conn, peer_addr)| {
                    let (conn, future) = ServerConn::new_plain_single_thread_fn(
                        &handle,
                        conn,
                        peer_addr,
                        Default::default(),
                        service,
                    );
                    *conn_for_thread.lock().unwrap() = Some(conn);
                    future
                });

                let shutdown_rx = shutdown_rx.then(|_| future::ready(()));
                let future = future.then(|_| future::ready(()));

                let shutdown_rx = assert_send_future::<(), _>(shutdown_rx);
                let future = assert_send_future::<(), _>(future);

                let shutdown_rx = Box::pin(shutdown_rx);
                let future = Box::pin(future);

                lp.block_on(future::select(shutdown_rx, future));
            })
            .expect("spawn");

        ServerOneConn {
            from_loop: from_loop_rx.recv().unwrap(),
            join_handle: Some(join_handle),
            shutdown_tx: Some(shutdown_tx),
            conn,
        }
    }
}

#[allow(dead_code)]
impl ServerOneConn {
    pub fn port(&self) -> u16 {
        self.from_loop.port
    }

    pub fn dump_state(&self) -> ConnStateSnapshot {
        let g = self.conn.lock().expect("lock");
        let conn = g.as_ref().expect("conn");
        Runtime::new()
            .unwrap()
            .block_on(conn.dump_state())
            .expect("dump_status")
    }
}

impl Drop for ServerOneConn {
    fn drop(&mut self) {
        drop(self.shutdown_tx.take().unwrap().send(()));
        self.join_handle.take().unwrap().join().ok();
    }
}
<commit_msg>Remove TODO<commit_after>use std::net::ToSocketAddrs;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

use futures::channel::oneshot;
use futures::future;
use futures::future::FutureExt;
use futures::future::TryFutureExt;

use httpbis;
use httpbis::for_test::*;
use httpbis::*;

use super::BIND_HOST;
use crate::assert_types::assert_send_future;
use std::thread::JoinHandle;
use tokio::runtime::Runtime;

/// Single connection HTTP/server.
/// Accepts only one connection.
pub struct ServerOneConn {
    from_loop: FromLoop,
    join_handle: Option<thread::JoinHandle<()>>,
    shutdown_tx: Option<oneshot::Sender<()>>,
    conn: Arc<Mutex<Option<ServerConn>>>,
}

struct FromLoop {
    port: u16,
}

impl ServerOneConn {
    pub fn new_fn<S>(port: u16, service: S) -> Self
    where
        S: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> httpbis::Result<()>
            + Send
            + Sync
            + 'static,
    {
        ServerOneConn::new_fn_impl(port, service)
    }

    #[allow(dead_code)]
    fn new_fn_impl<S>(port: u16, service: S) -> Self
    where
        S: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> httpbis::Result<()>
            + Send
            + Sync
            + 'static,
    {
        let (from_loop_tx, from_loop_rx) = std::sync::mpsc::channel();
        let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();

        let conn: Arc<Mutex<Option<ServerConn>>> = Default::default();

        let conn_for_thread = conn.clone();

        let join_handle: JoinHandle<()> = thread::Builder::new()
            .name("server_one_conn".to_owned())
            .spawn(move || {
                let mut lp = Runtime::new().unwrap();

                let mut listener = lp
                    .block_on(tokio::net::TcpListener::bind(
                        &(BIND_HOST, port).to_socket_addrs().unwrap().next().unwrap(),
                    ))
                    .unwrap();

                let actual_port = listener.local_addr().unwrap().port();
                from_loop_tx
                    .send(FromLoop { port: actual_port })
                    .ok()
                    .unwrap();

                let handle = lp.handle().clone();

                let conn = listener.accept().map_err(httpbis::Error::from);

                let future = conn.and_then(move |(conn, peer_addr)| {
                    drop(listener);

                    let (conn, future) = ServerConn::new_plain_single_thread_fn(
                        &handle,
                        conn,
                        peer_addr,
                        Default::default(),
                        service,
                    );
                    *conn_for_thread.lock().unwrap() = Some(conn);
                    future
                });

                let shutdown_rx = shutdown_rx.then(|_| future::ready(()));
                let future = future.then(|_| future::ready(()));

                let shutdown_rx = assert_send_future::<(), _>(shutdown_rx);
                let future = assert_send_future::<(), _>(future);

                let shutdown_rx = Box::pin(shutdown_rx);
                let future = Box::pin(future);

                lp.block_on(future::select(shutdown_rx, future));
            })
            .expect("spawn");

        ServerOneConn {
            from_loop: from_loop_rx.recv().unwrap(),
            join_handle: Some(join_handle),
            shutdown_tx: Some(shutdown_tx),
            conn,
        }
    }
}

#[allow(dead_code)]
impl ServerOneConn {
    pub fn port(&self) -> u16 {
        self.from_loop.port
    }

    pub fn dump_state(&self) -> ConnStateSnapshot {
        let g = self.conn.lock().expect("lock");
        let conn = g.as_ref().expect("conn");
        Runtime::new()
            .unwrap()
            .block_on(conn.dump_state())
            .expect("dump_status")
    }
}

impl Drop for ServerOneConn {
    fn drop(&mut self) {
        drop(self.shutdown_tx.take().unwrap().send(()));
        self.join_handle.take().unwrap().join().ok();
    }
}
<|endoftext|>