<commit_before>extern crate glib_sys as glib;
extern crate libc;

use super::janus;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::ops::Deref;
use std::os::raw::c_char;

pub type RawSdp = janus::sdp::janus_sdp;
pub type MediaType = janus::sdp::janus_sdp_mtype;
pub type MediaDirection = janus::sdp::janus_sdp_mdirection;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus audio codecs. See utils.c.
pub enum AudioCodec {
    Opus,
    Pcmu,
    Pcma,
    G722,
    Isac16,
    Isac32,
}

impl AudioCodec {
    pub fn to_str(&self) -> &'static str {
        match *self {
            AudioCodec::Opus => "opus",
            AudioCodec::Pcmu => "pcmu",
            AudioCodec::Pcma => "pcma",
            AudioCodec::G722 => "g722",
            AudioCodec::Isac16 => "isac16",
            AudioCodec::Isac32 => "isac32",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus video codecs. See utils.c.
pub enum VideoCodec {
    Vp8,
    Vp9,
    H264,
}

impl VideoCodec {
    pub fn to_str(&self) -> &'static str {
        match *self {
            VideoCodec::Vp8 => "vp8",
            VideoCodec::Vp9 => "vp9",
            VideoCodec::H264 => "h264",
        }
    }
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Parameters controlling SDP offer answering behavior. Used as keys in the parameter list
/// for janus_sdp_generate_answer. See sdp-utils.h in the Janus source for more details.
pub enum OfferAnswerParameters {
    /// Used to signal the end of the offer-answer parameter list.
    Done = 0,
    /// Whether to accept or reject audio.
    Audio = 1,
    /// Whether to accept or reject video.
    Video = 2,
    /// Whether to accept or reject data.
    Data = 3,
    /// The MediaDirection for the audio stream.
    AudioDirection = 4,
    /// The MediaDirection for the video stream.
    VideoDirection = 5,
    /// The AudioCodec for the audio stream.
    AudioCodec = 6,
    /// The VideoCodec for the video stream.
    VideoCodec = 7,
    /// The payload type for the audio stream.
    AudioPayloadType = 8,
    /// The payload type for the video stream.
    VideoPayloadType = 9,
    /// Whether to negotiate telephone events.
    AudioDtmf = 10,
    /// Whether to add RTCP-FB attributes.
    VideoRtcpfbDefaults = 11,
    /// Whether to add attributes for H.264 video.
    VideoH264Fmtp = 12,
}

/// An SDP session description.
pub struct Sdp {
    contents: *mut RawSdp,
}

impl Deref for Sdp {
    type Target = RawSdp;

    fn deref(&self) -> &RawSdp {
        unsafe { &*self.contents }
    }
}

impl Drop for Sdp {
    fn drop(&mut self) {
        unsafe { janus::sdp::janus_sdp_free(self.contents) }
    }
}

/// A C-style string which was allocated using glibc.
pub struct GLibString<'a> {
    pub contents: &'a CStr,
}

impl<'a> Deref for GLibString<'a> {
    type Target = CStr;

    fn deref(&self) -> &CStr {
        return self.contents;
    }
}

impl<'a> Drop for GLibString<'a> {
    fn drop(&mut self) {
        unsafe { glib::g_free(self.contents.as_ptr() as *mut _) }
    }
}

#[derive(Debug)]
/// An error emitted by Janus when attempting to parse a client-supplied SDP.
pub struct SdpParsingError {
    pub details: String,
}

impl fmt::Display for SdpParsingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for SdpParsingError {
    fn description(&self) -> &str {
        &self.details
    }
}

/// Parses an SDP offer string from a client into a structured SDP object.
pub fn parse_sdp(offer: CString) -> Result<Sdp, Box<Error>> {
    let mut error_buffer = Vec::<u8>::with_capacity(512);
    let error_ptr = error_buffer.as_mut_ptr() as *mut c_char;
    let result = unsafe { janus::sdp::janus_sdp_parse(offer.as_ptr(), error_ptr, error_buffer.capacity()) };
    if result.is_null() {
        unsafe { error_buffer.set_len(libc::strlen(error_ptr)) }
        Err(Box::new(SdpParsingError {
            details: CString::new(error_buffer)?.into_string()?,
        }))
    } else {
        Ok(Sdp { contents: result })
    }
}

/// Given an SDP offer from a client, generates an SDP answer.
pub fn answer_sdp(sdp: &Sdp) -> Sdp {
    let result = unsafe { janus::sdp::janus_sdp_generate_answer(sdp.contents, OfferAnswerParameters::Done) };
    Sdp { contents: result }
}

/// Writes a structured SDP object into a string.
pub fn write_sdp(answer: &Sdp) -> GLibString {
    unsafe {
        GLibString {
            contents: CStr::from_ptr(janus::sdp::janus_sdp_write(answer.contents)),
        }
    }
}
<commit_msg>Convert answer_sdp to macro<commit_after>extern crate glib_sys as glib;
extern crate libc;

use super::janus;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::ops::Deref;
use std::os::raw::c_char;
pub use janus::sdp::janus_sdp_generate_answer as generate_answer;

pub type RawSdp = janus::sdp::janus_sdp;
pub type MediaType = janus::sdp::janus_sdp_mtype;
pub type MediaDirection = janus::sdp::janus_sdp_mdirection;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus audio codecs. See utils.c.
pub enum AudioCodec {
    Opus,
    Pcmu,
    Pcma,
    G722,
    Isac16,
    Isac32,
}

impl AudioCodec {
    pub fn to_str(&self) -> &'static str {
        match *self {
            AudioCodec::Opus => "opus",
            AudioCodec::Pcmu => "pcmu",
            AudioCodec::Pcma => "pcma",
            AudioCodec::G722 => "g722",
            AudioCodec::Isac16 => "isac16",
            AudioCodec::Isac32 => "isac32",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus video codecs. See utils.c.
pub enum VideoCodec {
    Vp8,
    Vp9,
    H264,
}

impl VideoCodec {
    pub fn to_str(&self) -> &'static str {
        match *self {
            VideoCodec::Vp8 => "vp8",
            VideoCodec::Vp9 => "vp9",
            VideoCodec::H264 => "h264",
        }
    }
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Parameters controlling SDP offer answering behavior. Used as keys in the parameter list
/// for janus_sdp_generate_answer. See sdp-utils.h in the Janus source for more details.
pub enum OfferAnswerParameters {
    /// Used to signal the end of the offer-answer parameter list.
    Done = 0,
    /// Whether to accept or reject audio.
    Audio = 1,
    /// Whether to accept or reject video.
    Video = 2,
    /// Whether to accept or reject data.
    Data = 3,
    /// The MediaDirection for the audio stream.
    AudioDirection = 4,
    /// The MediaDirection for the video stream.
    VideoDirection = 5,
    /// The AudioCodec for the audio stream.
    AudioCodec = 6,
    /// The VideoCodec for the video stream.
    VideoCodec = 7,
    /// The payload type for the audio stream.
    AudioPayloadType = 8,
    /// The payload type for the video stream.
    VideoPayloadType = 9,
    /// Whether to negotiate telephone events.
    AudioDtmf = 10,
    /// Whether to add RTCP-FB attributes.
    VideoRtcpfbDefaults = 11,
    /// Whether to add attributes for H.264 video.
    VideoH264Fmtp = 12,
}

/// An SDP session description.
pub struct Sdp {
    pub contents: *mut RawSdp,
}

impl Sdp {
    pub fn new(ptr: *mut RawSdp) -> Sdp {
        Sdp { contents: ptr }
    }
}

impl Deref for Sdp {
    type Target = RawSdp;

    fn deref(&self) -> &RawSdp {
        unsafe { &*self.contents }
    }
}

impl Drop for Sdp {
    fn drop(&mut self) {
        unsafe { janus::sdp::janus_sdp_free(self.contents) }
    }
}

/// A C-style string which was allocated using glibc.
pub struct GLibString<'a> {
    pub contents: &'a CStr,
}

impl<'a> Deref for GLibString<'a> {
    type Target = CStr;

    fn deref(&self) -> &CStr {
        return self.contents;
    }
}

impl<'a> Drop for GLibString<'a> {
    fn drop(&mut self) {
        unsafe { glib::g_free(self.contents.as_ptr() as *mut _) }
    }
}

#[derive(Debug)]
/// An error emitted by Janus when attempting to parse a client-supplied SDP.
pub struct SdpParsingError {
    pub details: String,
}

impl fmt::Display for SdpParsingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for SdpParsingError {
    fn description(&self) -> &str {
        &self.details
    }
}

#[macro_export]
/// Given an SDP offer from a client, generates an SDP answer.
macro_rules! answer_sdp {
    ($sdp:expr $(, $param:expr, $value:expr),*) => {{
        let result = unsafe {
            $crate::sdp::generate_answer(
                $sdp.contents,
                $($param, $value,)*
                $crate::sdp::OfferAnswerParameters::Done
            )
        };
        $crate::sdp::Sdp::new(result)
    }}
}

/// Parses an SDP offer string from a client into a structured SDP object.
pub fn parse_sdp(offer: CString) -> Result<Sdp, Box<Error>> {
    let mut error_buffer = Vec::<u8>::with_capacity(512);
    let error_ptr = error_buffer.as_mut_ptr() as *mut c_char;
    let result = unsafe { janus::sdp::janus_sdp_parse(offer.as_ptr(), error_ptr, error_buffer.capacity()) };
    if result.is_null() {
        unsafe { error_buffer.set_len(libc::strlen(error_ptr)) }
        Err(Box::new(SdpParsingError {
            details: CString::new(error_buffer)?.into_string()?,
        }))
    } else {
        Ok(Sdp { contents: result })
    }
}

/// Writes a structured SDP object into a string.
pub fn write_sdp(answer: &Sdp) -> GLibString {
    unsafe {
        GLibString {
            contents: CStr::from_ptr(janus::sdp::janus_sdp_write(answer.contents)),
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::slice::ref_slice;

use exec;
use eval::{self, DataMode};
use session::Process;
use resolve::types::{self, Shape};
use resolve::scope::Item;
use connection_io::{ConnectionRead, ConnectionWrite};
use ast::Value;

extern crate vcd;

fn shape_to_scope(s: &Shape) -> (vcd::Scope, Vec<vcd::IdCode>) {
    let mut ids = Vec::new();

    fn scope(ids: &mut Vec<vcd::IdCode>, l: &[Shape], name: String) -> vcd::Scope {
        vcd::Scope {
            scope_type: vcd::ScopeType::Module,
            identifier: name,
            children: l.iter().enumerate()
                .map(|(i, x)| inner(ids, x, i.to_string())).collect()
        }
    }

    fn inner(ids: &mut Vec<vcd::IdCode>, s: &Shape, name: String) -> vcd::ScopeItem {
        match *s {
            Shape::Val(_, _) => {
                let code = vcd::IdCode::from(ids.len() as u32);
                ids.push(code);

                vcd::ScopeItem::Var( vcd::Var {
                    var_type: vcd::VarType::Wire,
                    size: 1,
                    code: code,
                    reference: name
                })
            }
            Shape::Tup(ref l) => vcd::ScopeItem::Scope(scope(ids, &l[..], name))
        }
    }

    let top = scope(&mut ids, match *s {
        Shape::Val(..) => ref_slice(s),
        Shape::Tup(ref l) => &l[..],
    }, "top".to_string());

    (top, ids)
}

struct VcdDown(Shape);
impl Process for VcdDown {
    fn run(&self, _: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool {
        let mut c = ConnectionWrite(downwards);
        let mut w = vcd::write::Writer::new(&mut c);

        let (scope, ids) = shape_to_scope(&self.0);

        w.header(&vcd::Header {
            scope: scope,
            ..Default::default()
        }).unwrap();

        let mut time = 0u64;

        fn map_value(v: Value) -> vcd::Value {
            match v {
                Value::Symbol(ref v) if &v[..] == "h" => vcd::Value::V1,
                Value::Symbol(ref v) if &v[..] == "l" => vcd::Value::V0,
                _ => vcd::Value::X
            }
        }

        // TODO: more optimized VCD output
        while let Ok(n) = upwards.recv() {
            w.timestamp(time).unwrap();
            time += 1;
            for (i, v) in ids.iter().zip(n.into_iter().map(map_value)) {
                w.change_scalar(*i, v).unwrap();
            }
        }

        true
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

fn shape_from_scope(s: &Shape, v: &vcd::Scope) -> Vec<vcd::IdCode> {
    let mut ids = Vec::new();

    fn inner_tuple(ids: &mut Vec<vcd::IdCode>, shapes: &[Shape], scope: &vcd::Scope) {
        for (child_shape, child_scope) in shapes.iter().zip(scope.children.iter()) {
            inner(ids, child_shape, child_scope);
        }
    }

    fn inner(ids: &mut Vec<vcd::IdCode>, shape: &Shape, scope_item: &vcd::ScopeItem) {
        match (shape, scope_item) {
            (&Shape::Val(..), &vcd::ScopeItem::Var(ref var)) => {
                ids.push(var.code)
            }
            (&Shape::Tup(ref t), &vcd::ScopeItem::Scope(ref scope)) => {
                inner_tuple(ids, &t[..], scope)
            }
            (shape, scope) => {
                panic!("Shape {:?} doesn't match scope {:?}", shape, scope)
            }
        }
    }

    match s {
        &Shape::Tup(ref t) => inner_tuple(&mut ids, &t[..], v),
        &Shape::Val(..) => {
            if let Some(first_child) = v.children.first() {
                inner(&mut ids, s, first_child);
            } else {
                panic!("Shape {:?} doesn't match scope {:?}", s, v)
            }
        }
    }

    ids
}

struct VcdUp(Shape);
impl Process for VcdUp {
    fn run(&self, _: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool {
        let mut c = io::BufReader::new(ConnectionRead(downwards));
        let mut r = vcd::read::Parser::new(&mut c);
        let h = r.parse_header().unwrap();
        let ids = shape_from_scope(&self.0, &h.scope);

        fn map_value(v: vcd::Value) ->  Value {
            Value::Symbol(match v {
                vcd::Value::V1 => "h",
                vcd::Value::V0 => "l",
                vcd::Value::X => "x",
                vcd::Value::Z => "z",
            }.to_string())
        }

        let mut time = 0;
        let mut next_time;
        let mut values = ids.iter().map(|_| Value::Symbol("x".to_string())).collect::<Vec<_>>();

        while upwards.alive {
            loop {
                match r.next() {
                    Some(Ok(vcd::Command::Timestamp(s))) => {
                        next_time = s;
                        break;
                    }
                    Some(Ok(vcd::Command::ChangeScalar(id, v))) => {
                        for (i, val) in ids.iter().zip(values.iter_mut()) {
                            if *i == id {
                                *val = map_value(v);
                                break;
                            }
                        }
                    }
                    Some(Ok(..)) => panic!("Invalid command in VCD body"),
                    Some(Err(e)) => {
                        println!("VCD error: {}", e);
                        return false;
                    }
                    None => return true
                }
            }

            while time < next_time {
                debug!("{} {}", time, next_time);
                if upwards.send(values.clone()).is_err() {
                    break;
                }
                time += 1;
            }
        }

        true
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

pub fn process(downward_shape: &Shape, arg: Item) -> Box<Process + 'static> {
    let dir = match *downward_shape {
        Shape::Val(types::Integer, dir) => dir,
        _ => panic!("Invalid shape {:?} below vcd::process", downward_shape)
    };

    let upward_shape = arg.into_shape(dir);

    match dir {
        DataMode { down: false, up: true } => box VcdUp(upward_shape),
        DataMode { down: true, up: false } => box VcdDown(upward_shape),
        _ => panic!("Invalid direction {:?} below vcd::process", downward_shape)
    }
}
<commit_msg>Update VCD API<commit_after>use std::io;
use std::slice::ref_slice;

use exec;
use eval::{self, DataMode};
use session::Process;
use resolve::types::{self, Shape};
use resolve::scope::Item;
use connection_io::{ConnectionRead, ConnectionWrite};
use ast::Value;

extern crate vcd;

fn shape_to_scope(s: &Shape) -> (vcd::Scope, Vec<vcd::IdCode>) {
    let mut ids = Vec::new();

    fn scope(ids: &mut Vec<vcd::IdCode>, l: &[Shape], name: String) -> vcd::Scope {
        vcd::Scope {
            scope_type: vcd::ScopeType::Module,
            identifier: name,
            children: l.iter().enumerate()
                .map(|(i, x)| inner(ids, x, i.to_string())).collect()
        }
    }

    fn inner(ids: &mut Vec<vcd::IdCode>, s: &Shape, name: String) -> vcd::ScopeItem {
        match *s {
            Shape::Val(_, _) => {
                let code = vcd::IdCode::from(ids.len() as u32);
                ids.push(code);

                vcd::ScopeItem::Var( vcd::Var {
                    var_type: vcd::VarType::Wire,
                    size: 1,
                    code: code,
                    reference: name
                })
            }
            Shape::Tup(ref l) => vcd::ScopeItem::Scope(scope(ids, &l[..], name))
        }
    }

    let top = scope(&mut ids, match *s {
        Shape::Val(..) => ref_slice(s),
        Shape::Tup(ref l) => &l[..],
    }, "top".to_string());

    (top, ids)
}

struct VcdDown(Shape);
impl Process for VcdDown {
    fn run(&self, _: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool {
        let mut c = ConnectionWrite(downwards);
        let mut w = vcd::Writer::new(&mut c);

        let (scope, ids) = shape_to_scope(&self.0);

        w.header(&vcd::Header {
            scope: scope,
            ..Default::default()
        }).unwrap();

        let mut time = 0u64;

        fn map_value(v: Value) -> vcd::Value {
            match v {
                Value::Symbol(ref v) if &v[..] == "h" => vcd::Value::V1,
                Value::Symbol(ref v) if &v[..] == "l" => vcd::Value::V0,
                _ => vcd::Value::X
            }
        }

        // TODO: more optimized VCD output
        while let Ok(n) = upwards.recv() {
            w.timestamp(time).unwrap();
            time += 1;
            for (i, v) in ids.iter().zip(n.into_iter().map(map_value)) {
                w.change_scalar(*i, v).unwrap();
            }
        }

        true
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

fn shape_from_scope(s: &Shape, v: &vcd::Scope) -> Vec<vcd::IdCode> {
    let mut ids = Vec::new();

    fn inner_tuple(ids: &mut Vec<vcd::IdCode>, shapes: &[Shape], scope: &vcd::Scope) {
        for (child_shape, child_scope) in shapes.iter().zip(scope.children.iter()) {
            inner(ids, child_shape, child_scope);
        }
    }

    fn inner(ids: &mut Vec<vcd::IdCode>, shape: &Shape, scope_item: &vcd::ScopeItem) {
        match (shape, scope_item) {
            (&Shape::Val(..), &vcd::ScopeItem::Var(ref var)) => {
                ids.push(var.code)
            }
            (&Shape::Tup(ref t), &vcd::ScopeItem::Scope(ref scope)) => {
                inner_tuple(ids, &t[..], scope)
            }
            (shape, scope) => {
                panic!("Shape {:?} doesn't match scope {:?}", shape, scope)
            }
        }
    }

    match s {
        &Shape::Tup(ref t) => inner_tuple(&mut ids, &t[..], v),
        &Shape::Val(..) => {
            if let Some(first_child) = v.children.first() {
                inner(&mut ids, s, first_child);
            } else {
                panic!("Shape {:?} doesn't match scope {:?}", s, v)
            }
        }
    }

    ids
}

struct VcdUp(Shape);
impl Process for VcdUp {
    fn run(&self, _: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool {
        let mut c = io::BufReader::new(ConnectionRead(downwards));
        let mut r = vcd::Parser::new(&mut c);
        let h = r.parse_header().unwrap();
        let ids = shape_from_scope(&self.0, &h.scope);

        fn map_value(v: vcd::Value) ->  Value {
            Value::Symbol(match v {
                vcd::Value::V1 => "h",
                vcd::Value::V0 => "l",
                vcd::Value::X => "x",
                vcd::Value::Z => "z",
            }.to_string())
        }

        let mut time = 0;
        let mut next_time;
        let mut values = ids.iter().map(|_| Value::Symbol("x".to_string())).collect::<Vec<_>>();

        while upwards.alive {
            loop {
                match r.next() {
                    Some(Ok(vcd::Command::Timestamp(s))) => {
                        next_time = s;
                        break;
                    }
                    Some(Ok(vcd::Command::ChangeScalar(id, v))) => {
                        for (i, val) in ids.iter().zip(values.iter_mut()) {
                            if *i == id {
                                *val = map_value(v);
                                break;
                            }
                        }
                    }
                    Some(Ok(..)) => panic!("Invalid command in VCD body"),
                    Some(Err(e)) => {
                        println!("VCD error: {}", e);
                        return false;
                    }
                    None => return true
                }
            }

            while time < next_time {
                debug!("{} {}", time, next_time);
                if upwards.send(values.clone()).is_err() {
                    break;
                }
                time += 1;
            }
        }

        true
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

pub fn process(downward_shape: &Shape, arg: Item) -> Box<Process + 'static> {
    let dir = match *downward_shape {
        Shape::Val(types::Integer, dir) => dir,
        _ => panic!("Invalid shape {:?} below vcd::process", downward_shape)
    };

    let upward_shape = arg.into_shape(dir);

    match dir {
        DataMode { down: false, up: true } => box VcdUp(upward_shape),
        DataMode { down: true, up: false } => box VcdDown(upward_shape),
        _ => panic!("Invalid direction {:?} below vcd::process", downward_shape)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate blas;
extern crate num;

use std::num::NumCast;
use std::vec::Vec as StdVec;
use self::blas::{
    Vector,
    VectorOperations,
};
use self::num::complex::{
    Complex32,
    Complex64,
};

pub struct Vec<T> {
    inc: i32,
    data: StdVec<T>,
}

impl<T> Vector<T> for Vec<T> {
    #[inline]
    fn inc(&self) -> i32 { self.inc }

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(self.data.len());
        l.unwrap()
    }

    #[inline]
    fn as_ptr(&self) -> *const T { self.data.as_slice().as_ptr() }

    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T { self.data.as_mut_slice().as_mut_ptr() }
}

impl VectorOperations<f32> for Vec<f32> {}
impl VectorOperations<f64> for Vec<f64> {}
impl VectorOperations<Complex32> for Vec<Complex32> {}
impl VectorOperations<Complex64> for Vec<Complex64> {}
<commit_msg>Add operators<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate blas;
extern crate num;

use std::num::NumCast;
use std::ops::{
    Add,
    Mul,
};
use std::vec::Vec as StdVec;
use self::blas::Vector;
use self::blas::default::Default;
use self::blas::vector::ops::{Copy, Axpy, Scal, Dot};

pub struct Vec<T> {
    inc: i32,
    data: StdVec<T>,
}

impl<T> Vec<T> {
    pub fn from_vec(vec: StdVec<T>) -> Vec<T> {
        Vec {
            inc: 1i32,
            data: vec,
        }
    }

    pub fn as_vec(&self) -> &StdVec<T> {
        &self.data
    }
}

impl<T> Vector<T> for Vec<T> {
    #[inline]
    fn inc(&self) -> i32 { self.inc }

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(self.data.len());
        l.unwrap()
    }

    #[inline]
    fn as_ptr(&self) -> *const T { self.data.as_slice().as_ptr() }

    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T { self.data.as_mut_slice().as_mut_ptr() }
}

impl<T: Copy> Clone for Vec<T> {
    fn clone(&self) -> Vec<T> {
        let n = self.data.len();
        let mut result = Vec {
            inc: self.inc,
            data: StdVec::with_capacity(n),
        };
        Copy::copy(self, &mut result);
        unsafe { result.data.set_len(n); }

        result
    }
}

impl<T: Copy + Axpy + Default> Add<Vec<T>, Vec<T>> for Vec<T> {
    fn add(&self, x: &Vec<T>) -> Vec<T> {
        let mut result = self.clone();
        let one: T = Default::one();
        Axpy::axpy(&one, x, &mut result);
        result
    }
}

impl<T: Copy + Scal> Mul<T, Vec<T>> for Vec<T> {
    fn mul(&self, alpha: &T) -> Vec<T> {
        let mut result = self.clone();
        Scal::scal(alpha, &mut result);
        result
    }
}

impl<T: Copy + Dot> Mul<Vec<T>, T> for Vec<T> {
    fn mul(&self, x: &Vec<T>) -> T {
        Dot::dot(self, x)
    }
}

#[cfg(test)]
mod tests {
    use vec::Vec;

    #[test]
    fn add() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = Vec::from_vec(vec![-1f32, 2f32]);

        assert_eq!((x + y).as_vec(), &vec![0f32, 4f32]);
    }
}

<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate blas;
extern crate num;

use std::num::NumCast;
use std::ops::{
    Add,
    Mul,
};
use std::vec::Vec as StdVec;
use self::blas::Vector;
use self::blas::default::Default;
use self::blas::matrix_vector::ops::{
    Ger,
    Gerc,
};
use self::blas::vector::ops::{
    Axpy,
    Copy,
    Dot,
    Dotc,
    Scal,
};
use Trans;
use mat::Mat;

pub struct Vec<T> {
    inc: i32,
    data: StdVec<T>,
}

impl<T> Vec<T> {
    pub fn from_vec(vec: StdVec<T>) -> Vec<T> {
        Vec {
            inc: 1i32,
            data: vec,
        }
    }

    pub fn as_vec(&self) -> &StdVec<T> {
        &self.data
    }
}

impl<T> Vector<T> for Vec<T> {
    #[inline]
    fn inc(&self) -> i32 { self.inc }

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(self.data.len());
        l.unwrap()
    }

    #[inline]
    fn as_ptr(&self) -> *const T { self.data.as_slice().as_ptr() }

    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T { self.data.as_mut_slice().as_mut_ptr() }
}

impl<T: Copy> Clone for Vec<T> {
    fn clone(&self) -> Vec<T> {
        let n = self.data.len();
        let mut result = Vec {
            inc: self.inc,
            data: StdVec::with_capacity(n),
        };
        Copy::copy(self, &mut result);
        unsafe { result.data.set_len(n); }

        result
    }
}

impl<T, V> Add<V, Vec<T>> for Vec<T>
where T: Axpy + Copy + Default,
      V: Vector<T>,
{
    fn add(&self, x: &V) -> Vec<T> {
        let mut result = self.clone();
        Axpy::axpy(&Default::one(), x, &mut result);
        result
    }
}

impl<T> Mul<T, Vec<T>> for Vec<T>
where T: Copy + Scal,
{
    fn mul(&self, alpha: &T) -> Vec<T> {
        let mut result = self.clone();
        Scal::scal(alpha, &mut result);
        result
    }
}

impl<T, V> Mul<Trans<V>, Mat<T>> for Vec<T>
where T: Copy + Default + Ger + Gerc,
      V: Vector<T>,
{
    fn mul(&self, x: &Trans<V>) -> Mat<T> {
        let v = x.into_inner();
        let rows = self.data.len();
        let cols: uint = NumCast::from(v.len()).unwrap();
        let mut result = Mat::zero(rows, cols);

        match x {
            &Trans::T(_) => Ger::ger(&Default::one(), self, v, &mut result),
            &Trans::H(_) => Gerc::gerc(&Default::one(), self, v, &mut result),
        }

        result
    }
}

impl<T, V> Mul<V, T> for Trans<Vec<T>>
where T: Copy + Dot + Dotc,
      V: Vector<T>,
{
    fn mul(&self, x: &V) -> T {
        match *self {
            Trans::T(ref v) => Dot::dot(v, x),
            Trans::H(ref v) => Dotc::dotc(v, x),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate num;

    use self::num::complex::Complex;
    use vec::Vec;
    use Trans::{
        T,
        H,
    };

    #[test]
    fn add() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = vec![-1f32, 2f32];

        assert_eq!((x + y).as_vec(), &vec![0f32, 4f32]);
    }

    #[test]
    fn scalar_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);

        assert_eq!((x * 3.0).as_vec(), &vec![3f32, 6f32]);
    }

    #[test]
    fn dot_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = vec![-1f32, 2f32];

        assert_eq!(T(x) * y, 3.0);
    }

    #[test]
    fn complex_conj() {
        let x = Vec::from_vec(vec![Complex::new(1f32, -1f32), Complex::new(1f32, -3f32)]);
        let y = vec![Complex::new(1f32, 2f32), Complex::new(1f32, 3f32)];

        assert_eq!(H(x) * y, Complex::new(-9f32, 9f32));
    }
}
<commit_msg>Shorten len impl<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate blas;
extern crate num;

use std::num::NumCast;
use std::ops::{
    Add,
    Mul,
};
use std::vec::Vec as StdVec;
use self::blas::Vector;
use self::blas::default::Default;
use self::blas::matrix_vector::ops::{
    Ger,
    Gerc,
};
use self::blas::vector::ops::{
    Axpy,
    Copy,
    Dot,
    Dotc,
    Scal,
};
use Trans;
use mat::Mat;

pub struct Vec<T> {
    inc: i32,
    data: StdVec<T>,
}

impl<T> Vec<T> {
    pub fn from_vec(vec: StdVec<T>) -> Vec<T> {
        Vec {
            inc: 1i32,
            data: vec,
        }
    }

    pub fn as_vec(&self) -> &StdVec<T> {
        &self.data
    }
}

impl<T> Vector<T> for Vec<T> {
    #[inline]
    fn inc(&self) -> i32 { self.inc }

    #[inline]
    fn len(&self) -> i32 { NumCast::from(self.data.len()).unwrap() }

    #[inline]
    fn as_ptr(&self) -> *const T { self.data.as_slice().as_ptr() }

    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T { self.data.as_mut_slice().as_mut_ptr() }
}

impl<T: Copy> Clone for Vec<T> {
    fn clone(&self) -> Vec<T> {
        let n = self.data.len();
        let mut result = Vec {
            inc: self.inc,
            data: StdVec::with_capacity(n),
        };
        Copy::copy(self, &mut result);
        unsafe { result.data.set_len(n); }

        result
    }
}

impl<T, V> Add<V, Vec<T>> for Vec<T>
where T: Axpy + Copy + Default,
      V: Vector<T>,
{
    fn add(&self, x: &V) -> Vec<T> {
        let mut result = self.clone();
        Axpy::axpy(&Default::one(), x, &mut result);
        result
    }
}

impl<T> Mul<T, Vec<T>> for Vec<T>
where T: Copy + Scal,
{
    fn mul(&self, alpha: &T) -> Vec<T> {
        let mut result = self.clone();
        Scal::scal(alpha, &mut result);
        result
    }
}

impl<T, V> Mul<Trans<V>, Mat<T>> for Vec<T>
where T: Copy + Default + Ger + Gerc,
      V: Vector<T>,
{
    fn mul(&self, x: &Trans<V>) -> Mat<T> {
        let v = x.into_inner();
        let rows = self.data.len();
        let cols: uint = NumCast::from(v.len()).unwrap();
        let mut result = Mat::zero(rows, cols);

        match x {
            &Trans::T(_) => Ger::ger(&Default::one(), self, v, &mut result),
            &Trans::H(_) => Gerc::gerc(&Default::one(), self, v, &mut result),
        }

        result
    }
}

impl<T, V> Mul<V, T> for Trans<Vec<T>>
where T: Copy + Dot + Dotc,
      V: Vector<T>,
{
    fn mul(&self, x: &V) -> T {
        match *self {
            Trans::T(ref v) => Dot::dot(v, x),
            Trans::H(ref v) => Dotc::dotc(v, x),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate num;

    use self::num::complex::Complex;
    use vec::Vec;
    use Trans::{
        T,
        H,
    };

    #[test]
    fn add() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = vec![-1f32, 2f32];

        assert_eq!((x + y).as_vec(), &vec![0f32, 4f32]);
    }

    #[test]
    fn scalar_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);

        assert_eq!((x * 3.0).as_vec(), &vec![3f32, 6f32]);
    }

    #[test]
    fn dot_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = vec![-1f32, 2f32];

        assert_eq!(T(x) * y, 3.0);
    }

    #[test]
    fn complex_conj() {
        let x = Vec::from_vec(vec![Complex::new(1f32, -1f32), Complex::new(1f32, -3f32)]);
        let y = vec![Complex::new(1f32, 2f32), Complex::new(1f32, 3f32)];

        assert_eq!(H(x) * y, Complex::new(-9f32, 9f32));
    }
}
<|endoftext|>


<commit_before>use super::{Open, Sink};
use std::{io, thread, time, process::exit};
use std::sync::mpsc::{sync_channel, SyncSender};
use gst::prelude::*;
use gst::*;
use gst_app::*;
use glib::MainLoop;
use zerocopy::*;

pub struct GstreamerSink {
    tx: SyncSender<Vec<u8>>,
    pipeline: gst::Pipeline
}

impl Open for GstreamerSink {
    fn open(device: Option<String>) -> GstreamerSink {
        gst::init();
        let pipeline_str_preamble = r#"appsrc caps="audio/x-raw,format=S16LE,layout=interleaved,channels=2,rate=44100" block=true max-bytes=4096 name=appsrc0 "#;
        let pipeline_str_rest = r#" ! audioconvert ! autoaudiosink"#;
        let pipeline_str : String = match device {
            Some(x) => format!("{}{}", pipeline_str_preamble, x),
            None => format!("{}{}", pipeline_str_preamble, pipeline_str_rest)
        };
        println!("Pipeline: {}", pipeline_str);

        gst::init().unwrap();
        let pipelinee = gst::parse_launch(&*pipeline_str).expect("New Pipeline error");
        let pipeline = pipelinee.dynamic_cast::<gst::Pipeline>().expect("Couldn't cast pipeline element at runtime!");
        let mut bus = pipeline.get_bus().expect("Couldn't get bus from pipeline");
        let mut mainloop = glib::MainLoop::new(None, false);
        let mut appsrce : gst::Element = pipeline.get_by_name("appsrc0").expect("Couldn't get appsrc from pipeline");
        let mut appsrc : gst_app::AppSrc = appsrce.dynamic_cast::<gst_app::AppSrc>().expect("Couldn't cast AppSrc element at runtime!");
        let bufferpool = gst::BufferPool::new();
        let appsrc_caps = appsrc.get_caps().expect("get appsrc caps failed");
        let mut conf = bufferpool.get_config();
        conf.set_params(Some(&appsrc_caps), 8192, 0, 0);
        bufferpool.set_config(conf).expect("Couldn't configure the buffer pool");
        bufferpool.set_active(true).expect("Couldn't activate buffer pool");

        let (tx, rx) = sync_channel::<Vec<u8>>(128);
        thread::spawn(move || {
            for data in rx {
                let mut buffer = bufferpool.acquire_buffer(None);
                if(!buffer.is_err()) {
                    let mut okbuffer = buffer.unwrap();
                    let mutbuf = okbuffer.make_mut();
                    mutbuf.set_size(data.len());
                    mutbuf.copy_from_slice(0, data.as_bytes());
                    let eat = appsrc.push_buffer(okbuffer);
                }
            }
        });

        thread::spawn(move || {
            unsafe {
                let thread_mainloop = mainloop;
                let watch_mainloop = thread_mainloop.clone();
                bus.add_watch(move |_, msg| {
                    use gst::MessageView;
                    match msg.view() {
                        MessageView::Eos(..) => watch_mainloop.quit(),
                        MessageView::Error(err) => {
                            println!(
                                "Error from {:?}: {} ({:?})",
                                err.get_src().map(|s| s.get_path_string()),
                                err.get_error(),
                                err.get_debug()
                            );
                            watch_mainloop.quit();
                        }
                        _ => (),
                    };

                    glib::Continue(true)
                })
                .expect("Failed to add bus watch");
                thread_mainloop.run();
            }
        });

        GstreamerSink {
            tx: tx,
            pipeline: pipeline
        }
    }
}

impl Sink for GstreamerSink {
    fn start(&mut self) -> io::Result<()> {
        self.pipeline.set_state(gst::State::Playing).expect("Unable to set the pipeline to the `Playing` state");
        Ok(())
    }
    fn stop(&mut self) -> io::Result<()> {
        self.pipeline.set_state(gst::State::Ready).expect("Unable to set the pipeline to the `Ready` state");
        Ok(())
    }
    fn write(&mut self, data: &[i16]) -> io::Result<()> {
        // Copy expensively (in to_vec()) to avoid thread synchronization
        let deighta : &[u8] = data.as_bytes();
        self.tx.send(deighta.to_vec()).expect("tx send failed in write function");
        Ok(())
    }
}<commit_msg>Mostly fix play/pause/stop behavior. Pause is latent.<commit_after>use super::{Open, Sink};
use std::{io, thread, time, process::exit};
use std::sync::mpsc::{sync_channel, SyncSender};
use gst::prelude::*;
use gst::*;
use gst_app::*;
use glib::MainLoop;
use zerocopy::*;

pub struct GstreamerSink {
    tx: SyncSender<Vec<u8>>,
    pipeline: gst::Pipeline
}

impl Open for GstreamerSink {
    fn open(device: Option<String>) -> GstreamerSink {
        gst::init();
        let pipeline_str_preamble = r#"appsrc caps="audio/x-raw,format=S16LE,layout=interleaved,channels=2,rate=44100" block=true max-bytes=4096 name=appsrc0 "#;
        let pipeline_str_rest = r#" ! audioconvert ! autoaudiosink"#;
        let pipeline_str : String = match device {
            Some(x) => format!("{}{}", pipeline_str_preamble, x),
            None => format!("{}{}", pipeline_str_preamble, pipeline_str_rest)
        };
        println!("Pipeline: {}", pipeline_str);

        gst::init().unwrap();
        let pipelinee = gst::parse_launch(&*pipeline_str).expect("New Pipeline error");
        let pipeline = pipelinee.dynamic_cast::<gst::Pipeline>().expect("Couldn't cast pipeline element at runtime!");
        let mut bus = pipeline.get_bus().expect("Couldn't get bus from pipeline");
        let mut mainloop = glib::MainLoop::new(None, false);
        let mut appsrce : gst::Element = pipeline.get_by_name("appsrc0").expect("Couldn't get appsrc from pipeline");
        let mut appsrc : gst_app::AppSrc = appsrce.dynamic_cast::<gst_app::AppSrc>().expect("Couldn't cast AppSrc element at runtime!");
        let bufferpool = gst::BufferPool::new();
        let appsrc_caps = appsrc.get_caps().expect("get appsrc caps failed");
        let mut conf = bufferpool.get_config();
        conf.set_params(Some(&appsrc_caps), 8192, 0, 0);
        bufferpool.set_config(conf).expect("Couldn't configure the buffer pool");
        bufferpool.set_active(true).expect("Couldn't activate buffer pool");

        let (tx, rx) = sync_channel::<Vec<u8>>(128);
        thread::spawn(move || {
            for data in rx {
                let mut buffer = bufferpool.acquire_buffer(None);
                if(!buffer.is_err()) {
                    let mut okbuffer = buffer.unwrap();
                    let mutbuf = okbuffer.make_mut();
                    mutbuf.set_size(data.len());
                    mutbuf.copy_from_slice(0, data.as_bytes());
                    let eat = appsrc.push_buffer(okbuffer);
                }
            }
        });

        thread::spawn(move || {
            unsafe {
                let thread_mainloop = mainloop;
                let watch_mainloop = thread_mainloop.clone();
                bus.add_watch(move |_, msg| {
                    use gst::MessageView;
                    match msg.view() {
                        MessageView::Eos(..) => watch_mainloop.quit(),
                        MessageView::Error(err) => {
                            println!(
                                "Error from {:?}: {} ({:?})",
                                err.get_src().map(|s| s.get_path_string()),
                                err.get_error(),
                                err.get_debug()
                            );
                            watch_mainloop.quit();
                        }
                        _ => (),
                    };

                    glib::Continue(true)
                })
                .expect("Failed to add bus watch");
                thread_mainloop.run();
            }
        });

        pipeline.set_state(gst::State::Playing).expect("Unable to set the pipeline to the `Playing` state");

        GstreamerSink {
            tx: tx,
            pipeline: pipeline
        }
    }
}

impl Sink for GstreamerSink {
    fn start(&mut self) -> io::Result<()> {
        Ok(())
    }
    fn stop(&mut self) -> io::Result<()> {
        Ok(())
    }
    fn write(&mut self, data: &[i16]) -> io::Result<()> {
        // Copy expensively (in to_vec()) to avoid thread synchronization
        let deighta : &[u8] = data.as_bytes();
        self.tx.send(deighta.to_vec()).expect("tx send failed in write function");
        Ok(())
    }
}<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

/// To run benchmarking experiment, RuBen creates two key required components:
/// * An object that implements LoadGenerator trait, which generates accounts and offline TXNs
///   that to be submitted during both setup stage and load-testing stage.
/// * Benchmarker: responsible for playing given requests (submit and wait TXN committed).
///
/// then it drives TXN submission/waiting process in the following flow:
///
///     // Generate accounts
///     faucet_account = bm.load_faucet_account();
///     accounts = txn_generator.gen_accounts(num_accounts);
///     bm.register_accounts(accounts);
///
///     // Generate and run setup requests
///     mint_txns = txn_generator.gen_setup_txn_requests(faucet_account, &mut accounts);
///     bm.submit_and_wait_txn_committed(faucet_account, setup_requests);
///
///     // Generate and run load requests
///     load_txns = txn_generator.gen_signed_txn_load(accounts);
///     bm.submit_and_wait_txn_committed(accounts, load_txns);
///
/// By conforming to the LoadGenerator APIs,
/// this flow is basically the same for different LoadGenerators/experiments.
use admission_control_proto::proto::admission_control_grpc::AdmissionControlClient;
use benchmark::{
    ruben_opt::{Opt, TransactionPattern},
    txn_generator::{
        convert_load_to_txn_requests, gen_repeated_txn_load, LoadGenerator,
        PairwiseTransferTxnGenerator, RingTransferTxnGenerator,
    },
    Benchmarker,
};
use client::AccountData;
use grpcio::{ChannelBuilder, EnvBuilder};
use logger::{self, prelude::*};
use metrics::metric_server::start_server;
use std::{ops::DerefMut, sync::Arc};

/// Play given TXN pattern with Benchmarker for several epochs and measure burst throughput,
/// e.g., the average committed txns per second. Since time is counted from submission
/// until all TXNs are committed, this measurement is in a sense the user-side throughput.
/// Each epoch plays the given TXN request pattern sequence repeatedly for several rounds.
pub(crate) fn measure_throughput<T: LoadGenerator + ?Sized>(
    bm: &mut Benchmarker,
    txn_generator: &mut T,
    faucet_account: &mut AccountData,
    args: &Opt,
) {
    // Generate testing accounts.
    let mut accounts: Vec<AccountData> = txn_generator.gen_accounts(args.num_accounts);
    bm.register_accounts(&accounts);

    // Submit setup/minting TXN requests.
    let setup_requests = txn_generator.gen_setup_txn_requests(faucet_account, &mut accounts);
    let mint_txns = convert_load_to_txn_requests(setup_requests);
    bm.mint_accounts(&mint_txns, faucet_account);

    // Submit TXN load and measure throughput.
    let mut txn_throughput_seq = vec![];
    for _ in 0..args.num_epochs {
        let repeated_tx_reqs = gen_repeated_txn_load(txn_generator, &mut accounts, args.num_rounds);
        let txn_throughput = bm.measure_txn_throughput(&repeated_tx_reqs, &mut accounts);
        txn_throughput_seq.push(txn_throughput);
    }
    info!(
        "{} epoch(s) of REQ/TXN throughput = {:?}",
        args.num_epochs, txn_throughput_seq
    );
}

fn create_ac_client(conn_addr: &str) -> AdmissionControlClient {
    let env_builder = Arc::new(EnvBuilder::new().name_prefix("ac-grpc-").build());
    let ch = ChannelBuilder::new(env_builder).connect(&conn_addr);
    AdmissionControlClient::new(ch)
}

/// Creat a vector of AdmissionControlClient and connect them to validators.
fn create_ac_clients(
    num_clients: usize,
    validator_addresses: &[String],
) -> Vec<AdmissionControlClient> {
    let mut clients: Vec<AdmissionControlClient> = vec![];
    for i in 0..num_clients {
        let index = i % validator_addresses.len();
        let client = create_ac_client(&validator_addresses[index]);
        clients.push(client);
    }
    clients
}

pub(crate) fn create_benchmarker_from_opt(args: &Opt) -> Benchmarker {
    // Create AdmissionControlClient instances.
    let clients = create_ac_clients(args.num_clients, &args.validator_addresses);
    let submit_rate = args.parse_submit_rate();
    // Ready to instantiate Benchmarker.
    Benchmarker::new(clients, args.stagger_range_ms, submit_rate)
}

/// Benchmarker is not a long-lived job, so starting a server and expecting it to be polled
/// continuously is not ideal. Directly pushing metrics when benchmarker is running
/// can be achieved by using Pushgateway.
fn try_start_metrics_server(args: &Opt) {
    if let Some(metrics_server_address) = &args.metrics_server_address {
        let address = metrics_server_address.clone();
        std::thread::spawn(move || {
            start_server(address);
        });
    }
}

fn main() {
    let _g = logger::set_default_global_logger(false, Some(256));
    info!("RuBen: the utility to (Ru)n (Ben)chmarker");
    let args = Opt::new_from_args();
    info!("Parsed arguments: {:#?}", args);
    try_start_metrics_server(&args);
    let mut bm = create_benchmarker_from_opt(&args);
    let mut faucet_account = bm.load_faucet_account(&args.faucet_key_file_path);
    let mut generator: Box<dyn LoadGenerator> = match args.txn_pattern {
        TransactionPattern::Ring => Box::new(RingTransferTxnGenerator::new()),
        TransactionPattern::Pairwise => Box::new(PairwiseTransferTxnGenerator::new()),
    };
    measure_throughput(&mut bm, generator.deref_mut(), &mut faucet_account, &args);
}

#[cfg(test)]
mod tests {
    use crate::{create_benchmarker_from_opt, measure_throughput};
    use benchmark::{
        ruben_opt::{Opt, TransactionPattern},
        txn_generator::RingTransferTxnGenerator,
        OP_COUNTER,
    };
    use libra_swarm::swarm::LibraSwarm;
    use rusty_fork::{rusty_fork_id, rusty_fork_test, rusty_fork_test_name};

    rusty_fork_test! {
        #[test]
        fn test_benchmarker_counters() {
            let (faucet_account_keypair, faucet_key_file_path, _temp_dir) =
                generate_keypair::load_faucet_key_or_create_default(None);
            let swarm = LibraSwarm::launch_swarm(
                4,      /* num_nodes */
                true,   /* disable_logging */
                faucet_account_keypair,
                false,  /* tee_logs */
                None,   /* config_dir */
            );
            let mut args = Opt {
                validator_addresses: Vec::new(),
                debug_address: None,
                swarm_config_dir: Some(String::from(
                    swarm.dir.as_ref().unwrap().as_ref().to_str().unwrap(),
                )),
                // Don't start metrics server as we are not testing with prometheus.
                metrics_server_address: None,
                faucet_key_file_path,
                num_accounts: 4,
                free_lunch: 10_000_000,
                num_clients: 4,
                stagger_range_ms: 1,
                num_rounds: 4,
                num_epochs: 2,
                txn_pattern: TransactionPattern::Ring,
                submit_rate: None,
            };
            args.try_parse_validator_addresses();
            let mut bm = create_benchmarker_from_opt(&args);
            let mut faucet_account = bm.load_faucet_account(&args.faucet_key_file_path);
            let mut ring_generator = RingTransferTxnGenerator::new();
            measure_throughput(
                &mut bm,
                &mut ring_generator,
                &mut faucet_account,
                &args
            );
            let requested_txns = OP_COUNTER.counter("requested_txns").get();
            let created_txns = OP_COUNTER.counter("created_txns").get();
            let sign_failed_txns = OP_COUNTER.counter("sign_failed_txns").get();
            assert_eq!(requested_txns, created_txns + sign_failed_txns);
            let accepted_txns = OP_COUNTER.counter("submit_txns.Accepted").get();
            let committed_txns = OP_COUNTER.counter("committed_txns").get();
            let timedout_txns = OP_COUNTER.counter("timedout_txns").get();
            // Why `<=`: timedout TXNs in previous epochs can be committed in the next epoch.
            assert!(accepted_txns <= committed_txns + timedout_txns);
        }
    }
}
<commit_msg>[benchmark] force different clients to use different gRPC completion queues<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

/// To run benchmarking experiment, RuBen creates two key required components:
/// * An object that implements LoadGenerator trait, which generates accounts and offline TXNs
///   that to be submitted during both setup stage and load-testing stage.
/// * Benchmarker: responsible for playing given requests (submit and wait TXN committed).
///
/// then it drives TXN submission/waiting process in the following flow:
///
///     // Generate accounts
///     faucet_account = bm.load_faucet_account();
///     accounts = txn_generator.gen_accounts(num_accounts);
///     bm.register_accounts(accounts);
///
///     // Generate and run setup requests
///     mint_txns = txn_generator.gen_setup_txn_requests(faucet_account, &mut accounts);
///     bm.submit_and_wait_txn_committed(faucet_account, setup_requests);
///
///     // Generate and run load requests
///     load_txns = txn_generator.gen_signed_txn_load(accounts);
///     bm.submit_and_wait_txn_committed(accounts, load_txns);
///
/// By conforming to the LoadGenerator APIs,
/// this flow is basically the same for different LoadGenerators/experiments.
use admission_control_proto::proto::admission_control_grpc::AdmissionControlClient;
use benchmark::{
    ruben_opt::{Opt, TransactionPattern},
    txn_generator::{
        convert_load_to_txn_requests, gen_repeated_txn_load, LoadGenerator,
        PairwiseTransferTxnGenerator, RingTransferTxnGenerator,
    },
    Benchmarker,
};
use client::AccountData;
use grpcio::{ChannelBuilder, EnvBuilder};
use logger::{self, prelude::*};
use metrics::metric_server::start_server;
use std::{ops::DerefMut, sync::Arc};

/// Play given TXN pattern with Benchmarker for several epochs and measure burst throughput,
/// e.g., the average committed txns per second. Since time is counted from submission
/// until all TXNs are committed, this measurement is in a sense the user-side throughput.
/// Each epoch plays the given TXN request pattern sequence repeatedly for several rounds.
pub(crate) fn measure_throughput<T: LoadGenerator + ?Sized>(
    bm: &mut Benchmarker,
    txn_generator: &mut T,
    faucet_account: &mut AccountData,
    args: &Opt,
) {
    // Generate testing accounts.
    let mut accounts: Vec<AccountData> = txn_generator.gen_accounts(args.num_accounts);
    bm.register_accounts(&accounts);

    // Submit setup/minting TXN requests.
    let setup_requests = txn_generator.gen_setup_txn_requests(faucet_account, &mut accounts);
    let mint_txns = convert_load_to_txn_requests(setup_requests);
    bm.mint_accounts(&mint_txns, faucet_account);

    // Submit TXN load and measure throughput.
    let mut txn_throughput_seq = vec![];
    for _ in 0..args.num_epochs {
        let repeated_tx_reqs = gen_repeated_txn_load(txn_generator, &mut accounts, args.num_rounds);
        let txn_throughput = bm.measure_txn_throughput(&repeated_tx_reqs, &mut accounts);
        txn_throughput_seq.push(txn_throughput);
    }
    info!(
        "{} epoch(s) of REQ/TXN throughput = {:?}",
        args.num_epochs, txn_throughput_seq
    );
}

/// Creates a client for AC with a unique user-agent.
///
/// In a benchmark environment, we want to emulate multiple concurrent
/// clients, even though all of them originate from the same benchmarker
/// process. We add a unique user-agent to bypass some of gRPC default
/// optimization that group connections from the same source onto
/// a single completion queue (making requests sequntial).
///
/// index: unique identifier for the channel, to uniquify clients
fn create_ac_client(index: usize, conn_addr: &str) -> AdmissionControlClient {
    let env_builder = Arc::new(EnvBuilder::new().name_prefix("ac-grpc-").build());
    let ch = ChannelBuilder::new(env_builder)
        .primary_user_agent(&format!("grpc/benchmark-client-{}", index))
        .connect(&conn_addr);
    AdmissionControlClient::new(ch)
}

/// Creat a vector of AdmissionControlClient and connect them to validators.
fn create_ac_clients(
    num_clients: usize,
    validator_addresses: &[String],
) -> Vec<AdmissionControlClient> {
    let mut clients: Vec<AdmissionControlClient> = vec![];
    for i in 0..num_clients {
        let index = i % validator_addresses.len();
        let client = create_ac_client(i, &validator_addresses[index]);
        clients.push(client);
    }
    clients
}

pub(crate) fn create_benchmarker_from_opt(args: &Opt) -> Benchmarker {
    // Create AdmissionControlClient instances.
    let clients = create_ac_clients(args.num_clients, &args.validator_addresses);
    let submit_rate = args.parse_submit_rate();
    // Ready to instantiate Benchmarker.
    Benchmarker::new(clients, args.stagger_range_ms, submit_rate)
}

/// Benchmarker is not a long-lived job, so starting a server and expecting it to be polled
/// continuously is not ideal. Directly pushing metrics when benchmarker is running
/// can be achieved by using Pushgateway.
fn try_start_metrics_server(args: &Opt) {
    if let Some(metrics_server_address) = &args.metrics_server_address {
        let address = metrics_server_address.clone();
        std::thread::spawn(move || {
            start_server(address);
        });
    }
}

fn main() {
    let _g = logger::set_default_global_logger(false, Some(256));
    info!("RuBen: the utility to (Ru)n (Ben)chmarker");
    let args = Opt::new_from_args();
    info!("Parsed arguments: {:#?}", args);
    try_start_metrics_server(&args);
    let mut bm = create_benchmarker_from_opt(&args);
    let mut faucet_account = bm.load_faucet_account(&args.faucet_key_file_path);
    let mut generator: Box<dyn LoadGenerator> = match args.txn_pattern {
        TransactionPattern::Ring => Box::new(RingTransferTxnGenerator::new()),
        TransactionPattern::Pairwise => Box::new(PairwiseTransferTxnGenerator::new()),
    };
    measure_throughput(&mut bm, generator.deref_mut(), &mut faucet_account, &args);
}

#[cfg(test)]
mod tests {
    use crate::{create_benchmarker_from_opt, measure_throughput};
    use benchmark::{
        ruben_opt::{Opt, TransactionPattern},
        txn_generator::RingTransferTxnGenerator,
        OP_COUNTER,
    };
    use libra_swarm::swarm::LibraSwarm;
    use rusty_fork::{rusty_fork_id, rusty_fork_test, rusty_fork_test_name};

    rusty_fork_test! {
        #[test]
        fn test_benchmarker_counters() {
            let (faucet_account_keypair, faucet_key_file_path, _temp_dir) =
                generate_keypair::load_faucet_key_or_create_default(None);
            let swarm = LibraSwarm::launch_swarm(
                4,      /* num_nodes */
                true,   /* disable_logging */
                faucet_account_keypair,
                false,  /* tee_logs */
                None,   /* config_dir */
            );
            let mut args = Opt {
                validator_addresses: Vec::new(),
                debug_address: None,
                swarm_config_dir: Some(String::from(
                    swarm.dir.as_ref().unwrap().as_ref().to_str().unwrap(),
                )),
                // Don't start metrics server as we are not testing with prometheus.
                metrics_server_address: None,
                faucet_key_file_path,
                num_accounts: 4,
                free_lunch: 10_000_000,
                num_clients: 4,
                stagger_range_ms: 1,
                num_rounds: 4,
                num_epochs: 2,
                txn_pattern: TransactionPattern::Ring,
                submit_rate: None,
            };
            args.try_parse_validator_addresses();
            let mut bm = create_benchmarker_from_opt(&args);
            let mut faucet_account = bm.load_faucet_account(&args.faucet_key_file_path);
            let mut ring_generator = RingTransferTxnGenerator::new();
            measure_throughput(
                &mut bm,
                &mut ring_generator,
                &mut faucet_account,
                &args
            );
            let requested_txns = OP_COUNTER.counter("requested_txns").get();
            let created_txns = OP_COUNTER.counter("created_txns").get();
            let sign_failed_txns = OP_COUNTER.counter("sign_failed_txns").get();
            assert_eq!(requested_txns, created_txns + sign_failed_txns);
            let accepted_txns = OP_COUNTER.counter("submit_txns.Accepted").get();
            let committed_txns = OP_COUNTER.counter("committed_txns").get();
            let timedout_txns = OP_COUNTER.counter("timedout_txns").get();
            // Why `<=`: timedout TXNs in previous epochs can be committed in the next epoch.
            assert!(accepted_txns <= committed_txns + timedout_txns);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Chad Williamson <chad@dahc.us>
//
// Use of this source code is governed by an MIT-syle license that can be
// found in the LICENSE file or at https://opensource.org/licenses/MIT.

// This file contains integration tests for the find command.
//
// Note: the `serial` macro is used on tests that make assumptions about the
// working directory, since we have at least one test that needs to change it.

use assert_cmd::Command;
use predicates::prelude::*;
use serial_test::serial;
use std::fs::File;
use std::io::Write;
use std::{env, io::ErrorKind};
use tempfile::Builder;

#[cfg(unix)]
use std::os::unix::fs::symlink;

#[cfg(windows)]
use std::os::windows::fs::{symlink_dir, symlink_file};

use common::test_helpers::*;

mod common;

// Variants of fix_up_slashes that properly escape the forward slashes for being
// in a regex.
#[cfg(windows)]
fn fix_up_regex_slashes(re: &str) -> String {
    re.replace("/", "\\\\")
}

#[cfg(not(windows))]
fn fix_up_regex_slashes(re: &str) -> String {
    re.to_owned()
}

#[serial(working_dir)]
#[test]
fn no_args() {
    Command::cargo_bin("find")
        .expect("found binary")
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("test_data"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_both_match() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "d", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("test_data"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_one_matches() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "f", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());
}

#[test]
fn matcher_with_side_effects_at_end() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();

    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-name", "test", "-delete"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(temp_dir.path().exists(), "temp dir should NOT be deleted");
}

#[test]
fn matcher_with_side_effects_in_front() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();

    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-delete", "-name", "test"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(!temp_dir.path().exists(), "temp dir should also be deleted");
}

// This could be covered by a unit test in principle... in practice, changing
// the working dir can't be done safely in unit tests unless `--test-threads=1`
// or `serial` goes everywhere, and it doesn't seem possible to get an
// appropriate `walkdir::DirEntry` for "." without actually changing dirs
// (or risking deletion of the repo itself).
#[serial(working_dir)]
#[test]
fn delete_on_dot_dir() {
    let temp_dir = Builder::new().prefix("example").tempdir().unwrap();
    let original_dir = env::current_dir().unwrap();
    env::set_current_dir(&temp_dir.path()).expect("working dir changed");

    // "." should be matched (confirmed by the print), but not deleted.
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[".", "-delete", "-print"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::diff(".\n"));

    env::set_current_dir(original_dir).expect("restored original working dir");

    assert!(temp_dir.path().exists(), "temp dir should still exist");
}

#[test]
fn regex_types() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();

    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("teeest");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-regex", &fix_up_regex_slashes(".*/tE+st")])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-iregex", &fix_up_regex_slashes(".*/tE+st")])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("teeest"));

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &temp_dir_path,
            "-regextype",
            "posix-basic",
            "-regex",
            &fix_up_regex_slashes(r".*/te\{1,3\}st"),
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("teeest"));

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &temp_dir_path,
            "-regextype",
            "posix-extended",
            "-regex",
            &fix_up_regex_slashes(".*/te{1,3}st"),
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("teeest"));
}

#[test]
fn empty_files() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();
    let temp_dir_path = temp_dir.path().to_string_lossy();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!("{}\n", temp_dir_path)));

    let test_file_path = temp_dir.path().join("test");
    let mut test_file = File::create(&test_file_path).unwrap();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!(
            "{}\n",
            test_file_path.to_string_lossy()
        )));

    let subdir_path = temp_dir.path().join("subdir");
    std::fs::create_dir(&subdir_path).unwrap();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty", "-sorted"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!(
            "{}\n{}\n",
            subdir_path.to_string_lossy(),
            test_file_path.to_string_lossy()
        )));

    write!(test_file, "x").unwrap();
    test_file.sync_all().unwrap();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty", "-sorted"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!(
            "{}\n",
            subdir_path.to_string_lossy(),
        )));
}

#[serial(working_dir)]
#[test]
fn find_printf() {
    #[cfg(unix)]
    {
        if let Err(e) = symlink("abbbc", "test_data/links/link-f") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("subdir", "test_data/links/link-d") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("missing", "test_data/links/link-missing") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("abbbc/x", "test_data/links/link-notdir") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("link-loop", "test_data/links/link-loop") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
    }
    #[cfg(windows)]
    {
        if let Err(e) = symlink_file("abbbc", "test_data/links/link-f") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink_dir("subdir", "test_data/links/link-d") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink_file("missing", "test_data/links/link-missing") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink_file("abbbc/x", "test_data/links/link-notdir") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
    }

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &fix_up_slashes("./test_data/simple"),
            "-sorted",
            "-printf",
            "%f %d %h %H %p %P %y\n",
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::diff(fix_up_slashes(
            "simple 0 ./test_data ./test_data/simple \
            ./test_data/simple  d\n\
            abbbc 1 ./test_data/simple ./test_data/simple \
            ./test_data/simple/abbbc abbbc f\n\
            subdir 1 ./test_data/simple ./test_data/simple \
            ./test_data/simple/subdir subdir d\n\
            ABBBC 2 ./test_data/simple/subdir ./test_data/simple \
            ./test_data/simple/subdir/ABBBC subdir/ABBBC f\n",
        )));

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &fix_up_slashes("./test_data/links"),
            "-sorted",
            "-type",
            "l",
            "-printf",
            "%f %l %y %Y\n",
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::diff(
            [
                "link-d subdir l d\n",
                "link-f abbbc l f\n",
                #[cfg(unix)]
                "link-loop link-loop l L\n",
                "link-missing missing l N\n",
                // We can't detect ENOTDIR on non-unix platforms yet.
                #[cfg(not(unix))]
                "link-notdir abbbc/x l ?\n",
                #[cfg(unix)]
                "link-notdir abbbc/x l N\n",
            ]
            .join(""),
        ));
}
<commit_msg>find: Add integration tests for -perm<commit_after>// Copyright 2021 Chad Williamson <chad@dahc.us>
//
// Use of this source code is governed by an MIT-syle license that can be
// found in the LICENSE file or at https://opensource.org/licenses/MIT.

// This file contains integration tests for the find command.
//
// Note: the `serial` macro is used on tests that make assumptions about the
// working directory, since we have at least one test that needs to change it.

use assert_cmd::Command;
use predicates::prelude::*;
use serial_test::serial;
use std::fs::File;
use std::io::Write;
use std::{env, io::ErrorKind};
use tempfile::Builder;

#[cfg(unix)]
use std::os::unix::fs::symlink;

#[cfg(windows)]
use std::os::windows::fs::{symlink_dir, symlink_file};

use common::test_helpers::*;

mod common;

// Variants of fix_up_slashes that properly escape the forward slashes for being
// in a regex.
#[cfg(windows)]
fn fix_up_regex_slashes(re: &str) -> String {
    re.replace("/", "\\\\")
}

#[cfg(not(windows))]
fn fix_up_regex_slashes(re: &str) -> String {
    re.to_owned()
}

#[serial(working_dir)]
#[test]
fn no_args() {
    Command::cargo_bin("find")
        .expect("found binary")
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("test_data"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_both_match() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "d", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("test_data"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_one_matches() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "f", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());
}

#[test]
fn matcher_with_side_effects_at_end() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();

    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-name", "test", "-delete"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(temp_dir.path().exists(), "temp dir should NOT be deleted");
}

#[test]
fn matcher_with_side_effects_in_front() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();

    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-delete", "-name", "test"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(!temp_dir.path().exists(), "temp dir should also be deleted");
}

// This could be covered by a unit test in principle... in practice, changing
// the working dir can't be done safely in unit tests unless `--test-threads=1`
// or `serial` goes everywhere, and it doesn't seem possible to get an
// appropriate `walkdir::DirEntry` for "." without actually changing dirs
// (or risking deletion of the repo itself).
#[serial(working_dir)]
#[test]
fn delete_on_dot_dir() {
    let temp_dir = Builder::new().prefix("example").tempdir().unwrap();
    let original_dir = env::current_dir().unwrap();
    env::set_current_dir(&temp_dir.path()).expect("working dir changed");

    // "." should be matched (confirmed by the print), but not deleted.
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[".", "-delete", "-print"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::diff(".\n"));

    env::set_current_dir(original_dir).expect("restored original working dir");

    assert!(temp_dir.path().exists(), "temp dir should still exist");
}

#[test]
fn regex_types() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();

    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("teeest");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-regex", &fix_up_regex_slashes(".*/tE+st")])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-iregex", &fix_up_regex_slashes(".*/tE+st")])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("teeest"));

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &temp_dir_path,
            "-regextype",
            "posix-basic",
            "-regex",
            &fix_up_regex_slashes(r".*/te\{1,3\}st"),
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("teeest"));

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &temp_dir_path,
            "-regextype",
            "posix-extended",
            "-regex",
            &fix_up_regex_slashes(".*/te{1,3}st"),
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("teeest"));
}

#[test]
fn empty_files() {
    let temp_dir = Builder::new().prefix("find_cmd_").tempdir().unwrap();
    let temp_dir_path = temp_dir.path().to_string_lossy();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!("{}\n", temp_dir_path)));

    let test_file_path = temp_dir.path().join("test");
    let mut test_file = File::create(&test_file_path).unwrap();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!(
            "{}\n",
            test_file_path.to_string_lossy()
        )));

    let subdir_path = temp_dir.path().join("subdir");
    std::fs::create_dir(&subdir_path).unwrap();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty", "-sorted"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!(
            "{}\n{}\n",
            subdir_path.to_string_lossy(),
            test_file_path.to_string_lossy()
        )));

    write!(test_file, "x").unwrap();
    test_file.sync_all().unwrap();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-empty", "-sorted"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(fix_up_slashes(&format!(
            "{}\n",
            subdir_path.to_string_lossy(),
        )));
}

#[serial(working_dir)]
#[test]
fn find_printf() {
    #[cfg(unix)]
    {
        if let Err(e) = symlink("abbbc", "test_data/links/link-f") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("subdir", "test_data/links/link-d") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("missing", "test_data/links/link-missing") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("abbbc/x", "test_data/links/link-notdir") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink("link-loop", "test_data/links/link-loop") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
    }
    #[cfg(windows)]
    {
        if let Err(e) = symlink_file("abbbc", "test_data/links/link-f") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink_dir("subdir", "test_data/links/link-d") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink_file("missing", "test_data/links/link-missing") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
        if let Err(e) = symlink_file("abbbc/x", "test_data/links/link-notdir") {
            if e.kind() != ErrorKind::AlreadyExists {
                panic!("Failed to create sym link: {:?}", e);
            }
        }
    }

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &fix_up_slashes("./test_data/simple"),
            "-sorted",
            "-printf",
            "%f %d %h %H %p %P %y\n",
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::diff(fix_up_slashes(
            "simple 0 ./test_data ./test_data/simple \
            ./test_data/simple  d\n\
            abbbc 1 ./test_data/simple ./test_data/simple \
            ./test_data/simple/abbbc abbbc f\n\
            subdir 1 ./test_data/simple ./test_data/simple \
            ./test_data/simple/subdir subdir d\n\
            ABBBC 2 ./test_data/simple/subdir ./test_data/simple \
            ./test_data/simple/subdir/ABBBC subdir/ABBBC f\n",
        )));

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[
            &fix_up_slashes("./test_data/links"),
            "-sorted",
            "-type",
            "l",
            "-printf",
            "%f %l %y %Y\n",
        ])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::diff(
            [
                "link-d subdir l d\n",
                "link-f abbbc l f\n",
                #[cfg(unix)]
                "link-loop link-loop l L\n",
                "link-missing missing l N\n",
                // We can't detect ENOTDIR on non-unix platforms yet.
                #[cfg(not(unix))]
                "link-notdir abbbc/x l ?\n",
                #[cfg(unix)]
                "link-notdir abbbc/x l N\n",
            ]
            .join(""),
        ));
}

#[cfg(unix)]
#[serial(working_dir)]
#[test]
fn find_perm() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-perm", "+rwx"])
        .assert()
        .success();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-perm", "u+rwX"])
        .assert()
        .success();

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-perm", "u=g"])
        .assert()
        .success();
}
<|endoftext|>


<commit_before>extern crate tetrahedrane;

use tetrahedrane::vid::*;
use tetrahedrane::start;
use tetrahedrane::shaders;

fn main() {
    let mut window = start::Window::new(640, 480, "Hello World!", 1 as usize);

    let mut shaders: Vec<Shader> = Vec::new();

    let mut triangle = Triangle::new(DepthPoint::new(0.0, -0.5, 3.0),
                                 DepthPoint::new(0.5, 0.5, 3.0),
                                 DepthPoint::new(-0.5, 0.5, 3.0),
                                 0.0, 0.0, 0.0,
                                 Color::new(200, 200, 200));

    shaders.push(shaders::disco_wireframe(1));

    triangle.shader_ids[0] = 1;

    loop {
        window.window.set(Color::new(20, 40, 60).orb_color());
        window.window.set(Color::new(20, 40, 60).orb_color());

        window.render(triangle, &shaders);

        window.window.sync();

        std::thread::sleep(std::time::Duration::from_millis(33));
    }
}<commit_msg>Added disco shader example.<commit_after>extern crate tetrahedrane;

use tetrahedrane::vid::*;
use tetrahedrane::start;
use tetrahedrane::shaders;

fn main() {
    let mut window = start::Window::new(640, 480, "Hello World!", 1 as usize);

    let mut shaders: Vec<Shader> = Vec::new();

    let mut triangle = Triangle::new(DepthPoint::new(0.0, -0.5, 3.0),
                                 DepthPoint::new(0.5, 0.5, 3.0),
                                 DepthPoint::new(-0.5, 0.5, 3.0),
                                 0.0, 0.0, 0.0,
                                 Color::new(200, 200, 200));

    shaders.push(shaders::disco_wireframe(1));

    triangle.shader_ids[0] = 1;

    loop {
        window.window.set(Color::new(20, 40, 60).orb_color());
        window.window.set(Color::new(20, 40, 60).orb_color());

        triangle.coord_rotate_x_y(0.0, 0.0, 0.01);

        window.render(triangle, &shaders);

        window.window.sync();

        std::thread::sleep(std::time::Duration::from_millis(33));
    }
}<|endoftext|>