<commit_before>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use notify::{self, RecommendedWatcher, Watcher};
use std::collections::BTreeMap;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::thread;

pub use luminance::{ProgramError, UniformUpdate};
use luminance::shader::stage;
pub use luminance_gl::gl33::{Program, Uniform};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: GetUni) -> Result<Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else {
        if let Some(gs) = gs {
          Program::new(None, &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(None, &vs, None, &fs, get_uni)
        }
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn read_stage<T, P>(path: P) -> Result<Stage<T>, StageError> where T: ShaderTypeable, P: AsRef<Path> {
  let path = path.as_ref().to_str().unwrap();

  info!("\tloading {:?} stage: \x1b[35m{}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

/// A `Program` wrapped by **ion**.
///
/// That wrapper is used to enable hot-reloading of shader programs.
pub struct WrappedProgram<'a, T> {
  receiver: mpsc::Receiver<PathBuf>,
  program: Program<T>,
  get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError> + 'a>,
  vs_path: PathBuf,
  fs_path: PathBuf,
  tess_path: Option<(PathBuf, PathBuf)>,
  gs_path: Option<PathBuf>
}

/// Add surveillance of a given `Program` by providing the path to all its shaders. When a change
/// occurs, the `Program` gets notified of the change via its `Receiver` channel part.
pub fn monitor_shader<P>(tess: &Option<(P, P)>, vs: &P, gs: &Option<P>, fs: &P, sx: mpsc::Sender<PathBuf>) where P: AsRef<Path> + Send + 'static {
  let (wsx, wrx) = mpsc::channel();
  let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

  // vertex shader
  watcher.watch(vs.as_ref());

  // fragment shader
  watcher.watch(fs.as_ref());

  // tessellation, if needed
  if let &Some((ref tcs, ref tes)) = tess {
    // tessellation control shader
    watcher.watch(tcs.as_ref());
    // tessellation evaluation shader
    watcher.watch(tes.as_ref());
  }

  // geometry shader, if needed
  if let &Some(ref gs) = gs {
    watcher.watch(gs.as_ref());
  }

  // start a new monitoring thread
  let _ = thread::spawn(move || {
    loop {
      if let Ok(notify::Event { path: Some(path), op: Ok(notify::op::WRITE) }) = wrx.recv() {
        deb!("{:?}’s content has changed!", path);
        sx.send(path);
      }
    }
  });
}

impl<'a, T> WrappedProgram<'a, T> {
  pub fn new<GetUni, P>(tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: GetUni) -> Result<Self, ProgramError>
      where GetUni: 'a + Fn(ProgramProxy) -> Result<T, ProgramError> + Clone,
            P: AsRef<Path> + Send + 'static {

    // load vertex and fragment shaders first
    let vs = try!(read_stage(vs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
    let fs = try!(read_stage(fs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

    let program = try!(match (&tess_path, &gs_path) {
      (&None, &None) => { // no tessellation nor geometry
        Program::new(None, &vs, None, &fs, get_uni.clone())
      },
      (&Some((ref tcs_path, ref tes_path)), &None) => { // tessellation without geometry
        let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni.clone())
      },
      (&None, &Some(ref gs_path)) => { // geometry without tessellation
        let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(None, &vs, Some(&gs), &fs, get_uni.clone())
      },
      (&Some((ref tcs_path, ref tes_path)), &Some(ref gs_path)) => { // tessellation and geometry
        let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni.clone())
      }
    });

    let (sx, rx) = mpsc::channel();

    monitor_shader(&tess_path, &vs_path, &gs_path, &fs_path, sx);

    let wrapped = WrappedProgram {
      receiver: rx,
      program: program,
      get_uni: Box::new(get_uni),
      vs_path: vs_path.as_ref().to_path_buf(),
      fs_path: fs_path.as_ref().to_path_buf(),
      tess_path: tess_path.map(|(tcs, tes)| (tcs.as_ref().to_path_buf(), tes.as_ref().to_path_buf())),
      gs_path: gs_path.map(|gs| gs.as_ref().to_path_buf())
    };

    Ok(wrapped)
  }
}
<commit_msg>Syncing shaders…<commit_after>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use notify::{self, RecommendedWatcher, Watcher};
use std::collections::BTreeMap;
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::thread;

pub use luminance::{ProgramError, UniformUpdate};
use luminance::shader::stage;
pub use luminance_gl::gl33::{Program, Uniform};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: GetUni) -> Result<Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else {
        if let Some(gs) = gs {
          Program::new(None, &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(None, &vs, None, &fs, get_uni)
        }
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn read_stage<T, P>(path: P) -> Result<Stage<T>, StageError> where T: ShaderTypeable, P: AsRef<Path> {
  let path = path.as_ref().to_str().unwrap();

  info!("\tloading {:?} stage: \x1b[35m{}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

/// A `Program` wrapped by **ion**.
///
/// That wrapper is used to enable hot-reloading of shader programs.
pub struct WrappedProgram<'a, T> {
  rx: mpsc::Receiver<PathBuf>,
  program: Program<T>,
  get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError> + 'a>,
  vs_path: PathBuf,
  fs_path: PathBuf,
  tess_path: Option<(PathBuf, PathBuf)>,
  gs_path: Option<PathBuf>
}

/// Add surveillance of a given `Program` by providing the path to all its shaders. When a change
/// occurs, the `Program` gets notified of the change via its `Receiver` channel part.
pub fn monitor_shader<P>(tess: &Option<(P, P)>, vs: &P, gs: &Option<P>, fs: &P, sx: mpsc::Sender<PathBuf>) where P: AsRef<Path> + Send + 'static {
  let (wsx, wrx) = mpsc::channel();
  let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

  // vertex shader
  watcher.watch(vs.as_ref());

  // fragment shader
  watcher.watch(fs.as_ref());

  // tessellation, if needed
  if let &Some((ref tcs, ref tes)) = tess {
    // tessellation control shader
    watcher.watch(tcs.as_ref());
    // tessellation evaluation shader
    watcher.watch(tes.as_ref());
  }

  // geometry shader, if needed
  if let &Some(ref gs) = gs {
    watcher.watch(gs.as_ref());
  }

  // start a new monitoring thread
  let _ = thread::spawn(move || {
    loop {
      if let Ok(notify::Event { path: Some(path), op: Ok(notify::op::WRITE) }) = wrx.recv() {
        deb!("{:?}’s content has changed!", path);
        sx.send(path);
      }
    }
  });
}

impl<'a, T> WrappedProgram<'a, T> {
  pub fn new<GetUni, P>(tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: GetUni) -> Result<Self, ProgramError>
      where GetUni: 'a + Fn(ProgramProxy) -> Result<T, ProgramError> + Clone,
            P: AsRef<Path> + Send + 'static {

    // load vertex and fragment shaders first
    let vs = try!(read_stage(vs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
    let fs = try!(read_stage(fs_path.as_ref()).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

    let program = try!(match (&tess_path, &gs_path) {
      (&None, &None) => { // no tessellation nor geometry
        Program::new(None, &vs, None, &fs, get_uni.clone())
      },
      (&Some((ref tcs_path, ref tes_path)), &None) => { // tessellation without geometry
        let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni.clone())
      },
      (&None, &Some(ref gs_path)) => { // geometry without tessellation
        let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(None, &vs, Some(&gs), &fs, get_uni.clone())
      },
      (&Some((ref tcs_path, ref tes_path)), &Some(ref gs_path)) => { // tessellation and geometry
        let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
        Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni.clone())
      }
    });

    let (sx, rx) = mpsc::channel();

    monitor_shader(&tess_path, &vs_path, &gs_path, &fs_path, sx);

    let wrapped = WrappedProgram {
      rx: rx,
      program: program,
      get_uni: Box::new(get_uni),
      vs_path: vs_path.as_ref().to_path_buf(),
      fs_path: fs_path.as_ref().to_path_buf(),
      tess_path: tess_path.map(|(tcs, tes)| (tcs.as_ref().to_path_buf(), tes.as_ref().to_path_buf())),
      gs_path: gs_path.map(|gs| gs.as_ref().to_path_buf())
    };

    Ok(wrapped)
  }

  /// Sync the embedded `Program`.
  pub fn sync(&mut self) {
    if let Ok(path) = self.rx.try_recv() {
      if path == self.vs_path {
        let vs = read_stage(path);
      } else if path == self.fs_path {
      } else if let Some((ref tcs, ref tes)) = self.tess_path {
        if path == *tcs {
        } else if path == *tes {
        }
      } else if Some(path) == self.gs_path {
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn named(pat: &Pat) -> Option<Name> {
    if let PatIdent(_, ident, _) = pat.node {
       Some(ident.node.name)
    } else { None }
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        check_pat(cx, pat, init, span, bindings);
        if let &Some(ref o) = init { check_expr(cx, o, bindings) }
    }
}

fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span,
        bindings: &mut Vec<Name>) where T: Deref<Target=Expr> {
    //TODO: match more stuff / destructuring
    named(pat).map(|name| {
        if let &Some(ref o) = init {
            if !in_external_macro(cx, o.span) {
                check_expr(cx, o, bindings);
            }
        }
        if bindings.contains(&name) {
            lint_shadow(cx, name, span, pat.span, init);
        }
        bindings.push(name);
    });
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) =>
            for ref arm in arms {
                for ref pat in &arm.pats {
                    //TODO: This is ugly, but needed to get the right type
                    check_pat(cx, pat, &Some(&**init), pat.span, bindings);
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &*arm.body, bindings);
            },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    path.segments.len() == 1 && path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path.segments.len() == 1 &&
            path.segments[0].identifier.name == name,
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<commit_msg>shadowing detection<commit_after>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        if let &Some(ref o) = init { check_expr(cx, o, bindings) }
        check_pat(cx, pat, init, span, bindings);
    }
}

fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span,
        bindings: &mut Vec<Name>) where T: Deref<Target=Expr> {
    //TODO: match more stuff / destructuring
    match pat.node {
        PatIdent(_, ref ident, ref inner) => {
            let name = ident.node.name;
            if pat_is_binding(&cx.tcx.def_map, pat) {
                if bindings.contains(&name) {
                    lint_shadow(cx, name, span, pat.span, init);
                }
                bindings.push(name);
            }
            if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); }
        },
        //PatEnum(Path, Option<Vec<P<Pat>>>),
        //PatQPath(QSelf, Path),
        //PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
        //PatTup(Vec<P<Pat>>),
        PatBox(ref inner) => {
            if let Some(ref initp) = *init {
                match initp.node {
                    ExprBox(_, ref inner_init) =>
                        check_pat(cx, inner, &Some(&**inner_init), span, bindings),
                    //TODO: ExprCall on Box::new
                    _ => check_pat(cx, inner, init, span, bindings),
                }
            } else {
                check_pat(cx, inner, init, span, bindings);
            }
        },
        //PatRegion(P<Pat>, Mutability),
        //PatRange(P<Expr>, P<Expr>),
        //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
        _ => (),
    }
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        //ExprCall
        //ExprMethodCall
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) => {
            check_expr(cx, init, bindings);
            for ref arm in arms {
                for ref pat in &arm.pats {
                    check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
                    //TODO: This is ugly, but needed to get the right type
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &arm.body, bindings);
            }
        },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    !path.global && path.segments.len() == 1 &&
        path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<|endoftext|>


<commit_before>use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Error;
use serde::de::Visitor;

use std::convert::Into;
use std::convert::From;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TaskStatus {
    Pending,
    Deleted,
    Completed,
    Waiting,
    Recurring
}

impl Serialize for TaskStatus {

    fn serialize<S>(&self, serializer: &mut S) -> Result<(), Error>
        where S: Serializer
    {
        serializer.serialize_str(
            match self {
                TaskStatus::Pending   => "pending",
                TaskStatus::Deleted   => "deleted",
                TaskStatus::Completed => "completed",
                TaskStatus::Waiting   => "waiting",
                TaskStatus::Recurring => "recurring",
            }
        )
    }

}

impl Deserialize for TaskStatus {
    fn deserialize<D>(deserializer: &mut D) -> Result<TaskStatus, Error>
        where D: Deserializer
    {
        struct TaskStatusVisitor;

        impl Visitor for TaskStatusVisitor {
            type Value = TaskStatus;

            fn visit_str<E>(&mut self, value: &str) -> Result<TaskStatus, E>
                where E: Error
            {
                match value {
                    "pending"   => Ok(TaskStatus::Pending),
                    "deleted"   => Ok(TaskStatus::Deleted),
                    "completed" => Ok(TaskStatus::Completed),
                    "waiting"   => Ok(TaskStatus::Waiting),
                    "recurring" => Ok(TaskStatus::Recurrin),
                    _           => Err(Error::custom("expected one of pending, deleted, completed, waiting, recurring")),
                }
            }
        }

        deserializer.deserialize(TaskStatusVisitor)
    }
}

<commit_msg>Fixup status<commit_after>use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Error;
use serde::de::Visitor;

use std::convert::Into;
use std::convert::From;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TaskStatus {
    Pending,
    Deleted,
    Completed,
    Waiting,
    Recurring
}

impl Serialize for TaskStatus {

    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_str(
            match self {
                &TaskStatus::Pending   => "pending",
                &TaskStatus::Deleted   => "deleted",
                &TaskStatus::Completed => "completed",
                &TaskStatus::Waiting   => "waiting",
                &TaskStatus::Recurring => "recurring",
            }
        )
    }

}

impl Deserialize for TaskStatus {
    fn deserialize<D>(deserializer: &mut D) -> Result<TaskStatus, D::Error>
        where D: Deserializer
    {
        struct TaskStatusVisitor;

        impl Visitor for TaskStatusVisitor {
            type Value = TaskStatus;

            fn visit_str<E>(&mut self, value: &str) -> Result<TaskStatus, E>
                where E: Error
            {
                match value {
                    "pending"   => Ok(TaskStatus::Pending),
                    "deleted"   => Ok(TaskStatus::Deleted),
                    "completed" => Ok(TaskStatus::Completed),
                    "waiting"   => Ok(TaskStatus::Waiting),
                    "recurring" => Ok(TaskStatus::Recurring),
                    _           => Err(Error::custom("expected one of pending, deleted, completed, waiting, recurring")),
                }
            }
        }

        deserializer.deserialize(TaskStatusVisitor)
    }
}

<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code)]
use kvproto::raftpb::HardState;
use raft::raft::{Raft, SoftState, StateRole};
use raft::storage::Storage;
use raft::progress::Progress;
use std::collections::HashMap;

#[derive(Default)]
pub struct Status {
    id: u64,
    pub hs: HardState,
    ss: SoftState,
    applied: u64,
    progress: HashMap<u64, Progress>,
}

impl Status {
    // new gets a copy of the current raft status.
    pub fn new<T: Storage>(raft: &Raft<T>) -> Status {
        let mut s = Status { id: raft.id, ..Default::default() };
        s.hs = raft.hard_state();
        s.ss = raft.soft_state();
        s.applied = raft.raft_log.get_applied();
        if s.ss.raft_state == StateRole::Leader {
            s.progress = raft.prs.clone();
        }
        s
    }
}
<commit_msg>raftstore: only compact replicated log (#433)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code)]
use kvproto::raftpb::HardState;
use raft::raft::{Raft, SoftState, StateRole};
use raft::storage::Storage;
use raft::progress::Progress;
use std::collections::HashMap;

#[derive(Default)]
pub struct Status {
    pub id: u64,
    pub hs: HardState,
    pub ss: SoftState,
    pub applied: u64,
    pub progress: HashMap<u64, Progress>,
}

impl Status {
    // new gets a copy of the current raft status.
    pub fn new<T: Storage>(raft: &Raft<T>) -> Status {
        let mut s = Status { id: raft.id, ..Default::default() };
        s.hs = raft.hard_state();
        s.ss = raft.soft_state();
        s.applied = raft.raft_log.get_applied();
        if s.ss.raft_state == StateRole::Leader {
            s.progress = raft.prs.clone();
        }
        s
    }
}
<|endoftext|>


<commit_before>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
}

fn parser<'a>(input: &'a [u8], is_start: &mut bool)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;

  if *is_start {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice     = i;
    *is_start = false;
  }

  metadata_parser(slice)
}

impl Stream {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  /// Returns information for the current stream.
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                      => break,
        Err(ErrorKind::EndOfInput) => break,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream.info.channels as usize;
      let block_size  = stream.info.max_block_size as usize;
      let output_size = block_size * channels;

      stream.output.reserve_exact(output_size);

      unsafe { stream.output.set_len(output_size) }

      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  /// Returns an iterator over the decoded samples.
  pub fn iter(&mut self) -> Iter {
    let samples_left = self.info.total_samples;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }

  fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a> {
  stream: &'a mut Stream,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a> Iterator for Iter<'a> {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      let frame_index = self.stream.frame_index;

      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a> IntoIterator for &'a mut Stream {
  type Item     = i32;
  type IntoIter = Iter<'a>;

  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<commit_msg>Add generic `StreamProducer` trait to `Stream`<commit_after>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

/// FLAC stream that decodes and hold file information.
pub struct Stream<P: StreamProducer> {
  info: StreamInfo,
  metadata: Vec<Metadata>,
  frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
  producer: P,
}

fn parser<'a>(input: &'a [u8], is_start: &mut bool)
              -> IResult<&'a [u8], Metadata> {
  let mut slice = input;

  if *is_start {
    let (i, _) = try_parse!(slice, tag!("fLaC"));

    slice     = i;
    *is_start = false;
  }

  metadata_parser(slice)
}

impl Stream {
  /// Constructor for the default state of a FLAC stream.
  ///
  /// This doesn't actually decode anything, it just hold the default values
  /// of each field.
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  /// Returns information for the current stream.
  pub fn info(&self) -> StreamInfo {
    self.info
  }

  /// Returns a slice of `Metadata`
  ///
  /// This slice excludes `StreamInfo`, which is located in `Stream::info`.
  /// Everything else is related to metadata for the FLAC stream is in the
  /// slice.
  pub fn metadata(&self) -> &[Metadata] {
    &self.metadata
  }

  /// Constructs a decoder with the given file name.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::NotFound` is returned when the given filename isn't found.
  /// * `ErrorKind::InvalidData` is returned when the data within the file
  ///   isn't valid FLAC data.
  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  /// Constructs a decoder with the given buffer.
  ///
  /// This constructor assumes that an entire FLAC file is in the buffer.
  ///
  /// # Failures
  ///
  /// * `ErrorKind::InvalidData` is returned when the data within the buffer
  ///   isn't valid FLAC data.
  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                      => break,
        Err(ErrorKind::EndOfInput) => break,
        Err(ErrorKind::Continue)   => continue,
        Err(_)                     => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream.info.channels as usize;
      let block_size  = stream.info.max_block_size as usize;
      let output_size = block_size * channels;

      stream.output.reserve_exact(output_size);

      unsafe { stream.output.set_len(output_size) }

      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  /// Returns an iterator over the decoded samples.
  pub fn iter(&mut self) -> Iter<P> {
    let samples_left = self.info.total_samples;

    Iter {
      stream: self,
      channel: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }

  fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata_parser(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                               -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

/// An iterator over a reference of the decoded FLAC stream.
pub struct Iter<'a, P> where P: 'a + StreamProducer {
  stream: &'a mut Stream<P>,
  channel: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a, P> Iterator for Iter<'a, P> where P: StreamProducer {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.sample_index == self.block_size {
      let frame_index = self.stream.frame_index;

      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel += 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
      self.samples_left -= 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a chance that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}

impl<'a, P> IntoIterator for &'a mut Stream<P>
 where P: StreamProducer {
  type Item     = i32;
  type IntoIter = Iter<'a, P>;

  fn into_iter(self) -> Self::IntoIter {
    self.iter()
  }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::SocketAddr;

use mio::deprecated::{TryRead, TryWrite};
use mio::tcp::TcpStream;
#[cfg(feature="ssl")]
use openssl::ssl::SslStream;
#[cfg(feature="ssl")]
use openssl::ssl::error::Error as SslError;
use bytes::{Buf, MutBuf};

use result::{Result, Error, Kind};

pub trait TryReadBuf: TryRead {
    fn try_read_buf<B: MutBuf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
        where Self : Sized
    {
        // Reads the length of the slice supplied by buf.mut_bytes into the buffer
        // This is not guaranteed to consume an entire datagram or segment.
        // If your protocol is msg based (instead of continuous stream) you should
        // ensure that your buffer is large enough to hold an entire segment (1532 bytes if not jumbo
        // frames)
        let res = self.try_read(unsafe { buf.mut_bytes() });

        if let Ok(Some(cnt)) = res {
            unsafe { buf.advance(cnt); }
        }

        res
    }
}

pub trait TryWriteBuf: TryWrite {
    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
        where Self : Sized
    {
        let res = self.try_write(buf.bytes());

        if let Ok(Some(cnt)) = res {
            buf.advance(cnt);
        }

        res
    }
}

impl<T: TryRead> TryReadBuf for T {}
impl<T: TryWrite> TryWriteBuf for T {}

use self::Stream::*;
pub enum Stream {
    Tcp(TcpStream),
    #[cfg(feature="ssl")]
    Tls {
        sock: SslStream<TcpStream>,
        negotiating: bool,
    }
}

impl Stream {

    pub fn tcp(stream: TcpStream) -> Stream {
        Tcp(stream)
    }

    #[cfg(feature="ssl")]
    pub fn tls(stream: SslStream<TcpStream>) -> Stream {
        Tls { sock: stream, negotiating: false }
    }

    #[cfg(feature="ssl")]
    pub fn is_tls(&self) -> bool {
        match *self {
            Tcp(_) => false,
            Tls {..} => true,
        }
    }

    pub fn evented(&self) -> &TcpStream {
        match *self {
            Tcp(ref sock) => sock,
            #[cfg(feature="ssl")]
            Tls { ref sock, ..} => sock.get_ref(),
        }
    }

    pub fn is_negotiating(&self) -> bool {
        match *self {
            Tcp(_) => false,
            #[cfg(feature="ssl")]
            Tls { sock: _, ref negotiating } => *negotiating,
        }

    }

    pub fn clear_negotiating(&mut self) -> Result<()> {
        match *self {
            Tcp(_) => Err(Error::new(Kind::Internal, "Attempted to clear negotiating flag on non ssl connection.")),
            #[cfg(feature="ssl")]
            Tls { sock: _, ref mut negotiating } => Ok(*negotiating = false),
        }
    }

    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            Tcp(ref sock) => sock.peer_addr(),
            #[cfg(feature="ssl")]
            Tls { ref sock, ..} => sock.get_ref().peer_addr(),
        }
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            Tcp(ref sock) => sock.local_addr(),
            #[cfg(feature="ssl")]
            Tls { ref sock, ..} => sock.get_ref().local_addr(),
        }
    }
}

impl TryRead for Stream {

    fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>> {
        match *self {
            Tcp(ref mut sock) => sock.try_read(buf),
            #[cfg(feature="ssl")]
            Tls { ref mut sock, ref mut negotiating } => {
                match sock.ssl_read(buf) {
                    Ok(cnt) => Ok(Some(cnt)),
                    Err(SslError::WantWrite(_)) => {
                        *negotiating = true;
                        Ok(None)
                    },
                    Err(SslError::WantRead(_)) => Ok(None),
                    Err(err) =>
                        Err(io::Error::new(io::ErrorKind::Other, err)),
                }
            }
        }
    }
}

impl TryWrite for Stream {

    fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>> {
        match *self {
            Tcp(ref mut sock) => sock.try_write(buf),
            #[cfg(feature="ssl")]
            Tls { ref mut sock, ref mut negotiating } => {

                *negotiating = false;

                match sock.ssl_write(buf) {
                    Ok(cnt) => Ok(Some(cnt)),
                    Err(SslError::WantRead(_)) => {
                        *negotiating = true;
                        Ok(None)
                    },
                    Err(SslError::WantWrite(_)) => Ok(None),
                    Err(err) =>
                        Err(io::Error::new(io::ErrorKind::Other, err)),
                }
            }
        }
    }
}
<commit_msg>chore: Remove deprecated Mio 5 TryRed/TryWrite<commit_after>use std::io;
use std::io::ErrorKind::WouldBlock;
use std::net::SocketAddr;

use mio::tcp::TcpStream;
#[cfg(feature="ssl")]
use openssl::ssl::SslStream;
#[cfg(feature="ssl")]
use openssl::ssl::error::Error as SslError;
use bytes::{Buf, MutBuf};

use result::{Result, Error, Kind};

fn map_non_block<T>(res: io::Result<T>) -> io::Result<Option<T>> {
    match res {
        Ok(value) => Ok(Some(value)),
        Err(err) => {
            if let WouldBlock = err.kind() {
                Ok(None)
            } else {
                Err(err)
            }
        }
    }
}

pub trait TryReadBuf: io::Read {
    fn try_read_buf<B: MutBuf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
        where Self : Sized
    {
        // Reads the length of the slice supplied by buf.mut_bytes into the buffer
        // This is not guaranteed to consume an entire datagram or segment.
        // If your protocol is msg based (instead of continuous stream) you should
        // ensure that your buffer is large enough to hold an entire segment (1532 bytes if not jumbo
        // frames)
        let res = map_non_block(self.read(unsafe { buf.mut_bytes() }));

        if let Ok(Some(cnt)) = res {
            unsafe { buf.advance(cnt); }
        }

        res
    }
}

pub trait TryWriteBuf: io::Write {
    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
        where Self : Sized
    {
        let res = map_non_block(self.write(buf.bytes()));

        if let Ok(Some(cnt)) = res {
            buf.advance(cnt);
        }

        res
    }
}

impl<T: io::Read> TryReadBuf for T {}
impl<T: io::Write> TryWriteBuf for T {}

use self::Stream::*;
pub enum Stream {
    Tcp(TcpStream),
    #[cfg(feature="ssl")]
    Tls {
        sock: SslStream<TcpStream>,
        negotiating: bool,
    }
}

impl Stream {

    pub fn tcp(stream: TcpStream) -> Stream {
        Tcp(stream)
    }

    #[cfg(feature="ssl")]
    pub fn tls(stream: SslStream<TcpStream>) -> Stream {
        Tls { sock: stream, negotiating: false }
    }

    #[cfg(feature="ssl")]
    pub fn is_tls(&self) -> bool {
        match *self {
            Tcp(_) => false,
            Tls {..} => true,
        }
    }

    pub fn evented(&self) -> &TcpStream {
        match *self {
            Tcp(ref sock) => sock,
            #[cfg(feature="ssl")]
            Tls { ref sock, ..} => sock.get_ref(),
        }
    }

    pub fn is_negotiating(&self) -> bool {
        match *self {
            Tcp(_) => false,
            #[cfg(feature="ssl")]
            Tls { sock: _, ref negotiating } => *negotiating,
        }

    }

    pub fn clear_negotiating(&mut self) -> Result<()> {
        match *self {
            Tcp(_) => Err(Error::new(Kind::Internal, "Attempted to clear negotiating flag on non ssl connection.")),
            #[cfg(feature="ssl")]
            Tls { sock: _, ref mut negotiating } => Ok(*negotiating = false),
        }
    }

    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            Tcp(ref sock) => sock.peer_addr(),
            #[cfg(feature="ssl")]
            Tls { ref sock, ..} => sock.get_ref().peer_addr(),
        }
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            Tcp(ref sock) => sock.local_addr(),
            #[cfg(feature="ssl")]
            Tls { ref sock, ..} => sock.get_ref().local_addr(),
        }
    }
}

impl io::Read for Stream {

    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Tcp(ref mut sock) => sock.read(buf),
            #[cfg(feature="ssl")]
            Tls { ref mut sock, ref mut negotiating } => {
                match sock.ssl_read(buf) {
                    Ok(cnt) => Ok(cnt),
                    Err(SslError::WantWrite(_)) => {
                        *negotiating = true;
                        Err(io::Error::new(io::ErrorKind::WouldBlock, "SSL wants writing"))
                    },
                    Err(SslError::WantRead(_)) => Err(io::Error::new(io::ErrorKind::WouldBlock, "SSL wants reading")),
                    Err(err) =>
                        Err(io::Error::new(io::ErrorKind::Other, err)),
                }
            }
        }
    }
}

impl io::Write for Stream {

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            Tcp(ref mut sock) => sock.write(buf),
            #[cfg(feature="ssl")]
            Tls { ref mut sock, ref mut negotiating } => {

                *negotiating = false;

                match sock.ssl_write(buf) {
                    Ok(cnt) => Ok(cnt),
                    Err(SslError::WantRead(_)) => {
                        *negotiating = true;
                        Err(io::Error::new(io::ErrorKind::WouldBlock, "SSL wants reading"))
                    },
                    Err(SslError::WantWrite(_)) => Err(io::Error::new(io::ErrorKind::WouldBlock, "SSL wants writing")),
                    Err(err) =>
                        Err(io::Error::new(io::ErrorKind::Other, err)),
                }
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            Tcp(ref mut sock) => sock.flush(),
            #[cfg(feature="ssl")]
            Tls { ref mut sock, negotiating: _ } => sock.flush(),
        }
    }
}
<|endoftext|>


<commit_before>use ll;
use pa::{PaError, PaResult};
use device::DeviceIndex;
use util::{to_pa_result, pa_time_to_duration};
use std::raw::Slice;
use std::mem;
use std::time::duration::Duration;
use libc::c_void;

#[repr(u32)]
pub enum StreamCallbackResult
{
    Continue = ll::paContinue,
    Complete = ll::paComplete,
    Abort = ll::paAbort,
}

pub type StreamCallback<'a, I, O> = |input: &[I], output: &mut [O], timeinfo: StreamTimeInfo, StreamCallbackFlags|:'a -> StreamCallbackResult;
pub type StreamFinishedCallback<'a> = ||:'a;

struct StreamUserData<'a, I, O>
{
    num_input: uint,
    num_output: uint,
    callback: Option<StreamCallback<'a, I, O>>,
    finished_callback: Option<StreamFinishedCallback<'a>>,
}

pub struct StreamTimeInfo
{
    pub input_adc_time: Duration,
    pub current_time: Duration,
    pub output_dac_time: Duration,
}

bitflags!(
    flags StreamCallbackFlags: u64 {
        static inputUnderflow = 0x01,
        static inputOverflow = 0x02,
        static outputUnderflow = 0x04,
        static outputOverflow = 0x08,
        static primingOutput = 0x10
    }
)

bitflags!(
    flags StreamFlags: u64 {
        static ClipOff                               = 0x00000001,
        static DitherOff                             = 0x00000002,
        static NeverDropInput                        = 0x00000004,
        static PrimeOutputBuffersUsingStreamCallback = 0x00000008,
        static PlatformSpecific                      = 0xFFFF0000
    }
)

extern "C" fn stream_callback<I, O>(input: *const c_void,
                                    output: *mut c_void,
                                    frame_count: ::libc::c_ulong,
                                    time_info: *const ll::PaStreamCallbackTimeInfo,
                                    status_flags: ll::PaStreamCallbackFlags,
                                    user_data: *mut c_void) -> ::libc::c_int
{
    let mut stream_data: Box<StreamUserData<I, O>> = unsafe { mem::transmute(user_data) };

    let input_buffer: &[I] = unsafe
    {
        mem::transmute(
            Slice { data: input as *const I, len: frame_count as uint * stream_data.num_input }
        )
    };
    let output_buffer: &mut [O] = unsafe
    {
        mem::transmute(
            Slice { data: output as *const O, len: frame_count as uint * stream_data.num_output }
        )
    };

    let flags = StreamCallbackFlags::from_bits_truncate(status_flags);

    let timeinfo = match unsafe { time_info.to_option() }
    {
        Some(ref info) => StreamTimeInfo { input_adc_time: pa_time_to_duration(info.inputBufferAdcTime),
                                           current_time: pa_time_to_duration(info.currentTime),
                                           output_dac_time: pa_time_to_duration(info.outputBufferDacTime) },
        None => StreamTimeInfo { input_adc_time: Duration::seconds(0),
                                 current_time: Duration::seconds(0),
                                 output_dac_time: Duration::seconds(0), },
    };

    let result = match stream_data.callback
    {
        Some(ref mut f) => (*f)(input_buffer, output_buffer, timeinfo, flags),
        None => Abort,
    };

    unsafe { mem::forget(stream_data); }

    result as i32
}

extern "C" fn stream_finished_callback<I, O>(user_data: *mut c_void)
{
    let mut stream_data: Box<StreamUserData<I, O>> = unsafe { mem::transmute(user_data) };
    match stream_data.finished_callback
    {
        Some(ref mut f) => (*f)(),
        None => {},
    };

    unsafe { mem::forget(stream_data); }
}

trait SampleType
{
    fn sample_format(_: Option<Self>) -> u64;
}
impl SampleType for f32 { fn sample_format(_: Option<f32>) -> u64 { 0x00000001 } }
impl SampleType for i32 { fn sample_format(_: Option<i32>) -> u64 { 0x00000002 } }
impl SampleType for i16 { fn sample_format(_: Option<i16>) -> u64 { 0x00000008 } }
impl SampleType for i8 { fn sample_format(_: Option<i8>) -> u64 { 0x00000010 } }
impl SampleType for u8 { fn sample_format(_: Option<u8>) -> u64 { 0x00000020 } }

fn get_sample_format<T: SampleType>() -> u64
{
    SampleType::sample_format(None::<T>)
}

pub fn get_sample_size<T: SampleType>() -> Result<uint, PaError>
{
    match unsafe { ll::Pa_GetSampleSize(get_sample_format::<T>()) }
    {
        n if n >= 0 => Ok(n as uint),
        m => to_pa_result(m).map(|_| 0),
    }
}

pub struct Stream<'a, I, O>
{
    pa_stream: *mut ll::PaStream,
    inputs: uint,
    outputs: uint,
    user_data: Box<StreamUserData<'a, I, O>>,
}

impl<'a, T: SampleType + Send> Stream<'a, T, T>
{
    pub fn open_default(num_input_channels: uint,
                        num_output_channels: uint,
                        sample_rate: f64,
                        frames_per_buffer: u64,
                        callback: Option<StreamCallback<'a, T, T>>)
                       -> Result<Stream<'a, T, T>, PaError>
    {
        unsafe
        {
            let callback_pointer = match callback
            {
                Some(_) => Some(stream_callback::<T, T>),
                None => None,
            };
            let userdata = box StreamUserData
            {
                num_input: num_input_channels,
                num_output: num_output_channels,
                callback: callback,
                finished_callback: None,
            };
            let mut pa_stream = ::std::ptr::mut_null();

            let ud_pointer: *mut c_void = mem::transmute(userdata);
            let ud_pointer_2 = ud_pointer.clone();
            let code = ll::Pa_OpenDefaultStream(&mut pa_stream as *mut *mut ll::PaStream,
                                                num_input_channels as i32,
                                                num_output_channels as i32,
                                                get_sample_format::<T>(),
                                                sample_rate,
                                                frames_per_buffer,
                                                callback_pointer,
                                                ud_pointer);
            match to_pa_result(code)
            {
                Ok(()) => Ok(Stream { pa_stream: pa_stream,
                                      user_data: mem::transmute(ud_pointer_2),
                                      inputs: num_input_channels,
                                      outputs: num_output_channels,
                             }),
                Err(v) => Err(v),
            }
        }
    }
}

impl<'a, I: SampleType + Send, O: SampleType + Send> Stream<'a, I, O>
{
    pub fn open(input: StreamParameters<I>,
                output: StreamParameters<O>,
                sample_rate: f64,
                frames_per_buffer: u64,
                flags: StreamFlags,
                callback: Option<StreamCallback<'a, I, O>>)
               -> Result<Stream<'a, I, O>, PaError>
    {
        unsafe
        {
            let callback_pointer = match callback
            {
                Some(_) => Some(stream_callback::<I, O>),
                None => None,
            };

            let user_data = box StreamUserData
            {
                num_input: input.channel_count,
                num_output: output.channel_count,
                callback: callback,
                finished_callback: None,
            };

            let mut pa_stream = ::std::ptr::mut_null();
            let ud_pointer: *mut c_void = mem::transmute(user_data);
            let ud_pointer_2 = ud_pointer.clone();

            let result = ll::Pa_OpenStream(&mut pa_stream,
                                                  &input.to_ll(),
                                                  &output.to_ll(),
                                                  sample_rate,
                                                  frames_per_buffer,
                                                  flags.bits,
                                                  callback_pointer,
                                                  ud_pointer);
            match to_pa_result(result)
            {
                Ok(()) => Ok(Stream { pa_stream: pa_stream,
                                      user_data: mem::transmute(ud_pointer_2),
                                      inputs: input.channel_count,
                                      outputs: output.channel_count,
                          }),
                Err(v) => Err(v),
            }
        }
    }

    pub fn start(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StartStream(self.pa_stream) })
    }

    pub fn stop(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StopStream(self.pa_stream) })
    }

    pub fn abort(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_AbortStream(self.pa_stream) })
    }

    fn close(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_CloseStream(self.pa_stream) })
    }

    pub fn is_stopped(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamStopped(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn is_active(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamActive(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn read_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamReadAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn write_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamWriteAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn write(&self, buffer: &[O]) -> PaResult
    {
        if self.outputs == 0 { return Err(::pa::CanNotWriteToAnInputOnlyStream) }

        let pointer = buffer.as_ptr() as *const c_void;
        let frames = (buffer.len() / self.outputs) as u64;

        to_pa_result(unsafe { ll::Pa_WriteStream(self.pa_stream, pointer, frames) })
    }

    pub fn read(&self, buffer: &mut [I]) -> PaResult
    {
        if self.inputs == 0 { return Err(::pa::CanNotReadFromAnOutputOnlyStream) }

        let pointer = buffer.as_mut_ptr() as *mut c_void;
        let frames = (buffer.len() / self.inputs) as u64;

        to_pa_result(unsafe { ll::Pa_ReadStream(self.pa_stream, pointer, frames) })
    }

    pub fn cpu_load(&self) -> f64
    {
        unsafe { ll::Pa_GetStreamCpuLoad(self.pa_stream) }
    }

    pub fn time(&self) -> Duration
    {
        let time = unsafe { ll::Pa_GetStreamTime(self.pa_stream) };
        pa_time_to_duration(time)
    }

    pub fn info(&self) -> Option<StreamInfo>
    {
        unsafe
        {
            ll::Pa_GetStreamInfo(self.pa_stream)
                .to_option()
                .map(|s| StreamInfo::from_ll(s))
        }
    }

    pub fn set_finished_callback(&mut self, finished_callback: StreamFinishedCallback<'a>) -> PaResult
    {
        self.user_data.finished_callback = Some(finished_callback);
        let callback_pointer = Some(stream_finished_callback::<I, O>);
        to_pa_result(unsafe { ll::Pa_SetStreamFinishedCallback(self.pa_stream, callback_pointer) })
    }

    pub fn unset_finished_callback(&mut self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_SetStreamFinishedCallback(self.pa_stream, None) })
    }
}

#[unsafe_destructor]
impl<'a, I: SampleType + Send, O: SampleType + Send> Drop for Stream<'a, I, O>
{
    fn drop(&mut self)
    {
        match self.close()
        {
            Err(v) => error!("Error: {}", v),
            Ok(_) => {},
        };
    }
}

pub struct StreamParameters<T>
{
    pub device: DeviceIndex,
    pub channel_count: uint,
    pub suggested_latency: Duration,
}

impl<T: SampleType> StreamParameters<T>
{
    fn to_ll(&self) -> ll::Struct_PaStreamParameters
    {
        ll::Struct_PaStreamParameters
        {
            device: self.device as i32,
            channelCount: self.channel_count as i32,
            sampleFormat: get_sample_format::<T>(),
            suggestedLatency: self.suggested_latency.num_milliseconds() as f64 / 1000.0,
            hostApiSpecificStreamInfo: ::std::ptr::mut_null(),
        }
    }
}

pub fn is_format_supported<I: SampleType, O: SampleType>(input: StreamParameters<I>, output: StreamParameters<O>, sample_rate: f64) -> PaResult
{
    to_pa_result(unsafe { ll::Pa_IsFormatSupported(&input.to_ll(), &output.to_ll(), sample_rate) })
}

pub struct StreamInfo
{
    pub input_latency: Duration,
    pub output_latency: Duration,
    pub sample_rate: f64,
}

impl StreamInfo
{
    fn from_ll(data: &ll::PaStreamInfo) -> StreamInfo
    {
        StreamInfo
        {
            input_latency: pa_time_to_duration(data.inputLatency),
            output_latency: pa_time_to_duration(data.outputLatency),
            sample_rate: data.sampleRate,
        }
    }
}

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

    // This test asserts that the sizes used by PortAudio are the same as
    // those used by Rust
    #[test]
    fn sample_sizes()
    {
        test_sample_size::<f32>();
        test_sample_size::<i32>();
        test_sample_size::<i16>();
        test_sample_size::<i8>();
        test_sample_size::<u8>();
    }

    fn test_sample_size<T: SampleType>()
    {
        use std::mem;

        let pa_size = super::get_sample_size::<T>().unwrap();
        let rs_size = mem::size_of::<T>();
        assert_eq!(rs_size, pa_size);
    }

    // In the FFI some assumptions are made as to how Some(p) and None are
    // represented when used as function pointers. This test asserts these
    // assumptions.
    #[test]
    fn option_pointer()
    {
        use std::{mem, ptr};
        use libc::c_void;

        unsafe
        {
            assert_eq!(mem::transmute::<Option<extern "C" fn()>, *const c_void>(Some(external_function)), external_function as *const c_void);
            assert_eq!(mem::transmute::<Option<extern "C" fn()>, *const c_void>(None)                   , ptr::null());
        }
    }

    extern "C" fn external_function() {}
}
<commit_msg>Some minor improvements to the stream code<commit_after>use ll;
use pa::{PaError, PaResult};
use device::DeviceIndex;
use util::{to_pa_result, pa_time_to_duration};
use std::raw::Slice;
use std::mem;
use std::time::duration::Duration;
use libc::c_void;

#[repr(u32)]
pub enum StreamCallbackResult
{
    Continue = ll::paContinue,
    Complete = ll::paComplete,
    Abort = ll::paAbort,
}

pub type StreamCallback<'a, I, O> = |input: &[I], output: &mut [O], timeinfo: StreamTimeInfo, StreamCallbackFlags|:'a -> StreamCallbackResult;
pub type StreamFinishedCallback<'a> = ||:'a;

struct StreamUserData<'a, I, O>
{
    num_input: uint,
    num_output: uint,
    callback: Option<StreamCallback<'a, I, O>>,
    finished_callback: Option<StreamFinishedCallback<'a>>,
}

pub struct StreamTimeInfo
{
    pub input_adc_time: Duration,
    pub current_time: Duration,
    pub output_dac_time: Duration,
}

impl StreamTimeInfo
{
    fn from_ll(data: &ll::PaStreamCallbackTimeInfo) -> StreamTimeInfo
    {
        StreamTimeInfo
        {
            input_adc_time: pa_time_to_duration(data.inputBufferAdcTime),
            current_time: pa_time_to_duration(data.currentTime),
            output_dac_time: pa_time_to_duration(data.outputBufferDacTime),
        }
    }
}

bitflags!(
    flags StreamCallbackFlags: u64 {
        static inputUnderflow = 0x01,
        static inputOverflow = 0x02,
        static outputUnderflow = 0x04,
        static outputOverflow = 0x08,
        static primingOutput = 0x10
    }
)

bitflags!(
    flags StreamFlags: u64 {
        static ClipOff                               = 0x00000001,
        static DitherOff                             = 0x00000002,
        static NeverDropInput                        = 0x00000004,
        static PrimeOutputBuffersUsingStreamCallback = 0x00000008,
        static PlatformSpecific                      = 0xFFFF0000
    }
)

extern "C" fn stream_callback<I, O>(input: *const c_void,
                                    output: *mut c_void,
                                    frame_count: ::libc::c_ulong,
                                    time_info: *const ll::PaStreamCallbackTimeInfo,
                                    status_flags: ll::PaStreamCallbackFlags,
                                    user_data: *mut c_void) -> ::libc::c_int
{
    let mut stream_data: Box<StreamUserData<I, O>> = unsafe { mem::transmute(user_data) };

    let input_buffer: &[I] = unsafe
    {
        mem::transmute(
            Slice { data: input as *const I, len: frame_count as uint * stream_data.num_input }
        )
    };
    let output_buffer: &mut [O] = unsafe
    {
        mem::transmute(
            Slice { data: output as *const O, len: frame_count as uint * stream_data.num_output }
        )
    };

    let flags = StreamCallbackFlags::from_bits_truncate(status_flags);
    let timeinfo = StreamTimeInfo::from_ll(unsafe { time_info.to_option() }.unwrap());

    let result = match stream_data.callback
    {
        Some(ref mut f) => (*f)(input_buffer, output_buffer, timeinfo, flags),
        None => Abort,
    };

    unsafe { mem::forget(stream_data); }

    result as i32
}

extern "C" fn stream_finished_callback<I, O>(user_data: *mut c_void)
{
    let mut stream_data: Box<StreamUserData<I, O>> = unsafe { mem::transmute(user_data) };
    match stream_data.finished_callback
    {
        Some(ref mut f) => (*f)(),
        None => {},
    };

    unsafe { mem::forget(stream_data); }
}

trait SampleType
{
    fn sample_format(_: Option<Self>) -> u64;
}
impl SampleType for f32 { fn sample_format(_: Option<f32>) -> u64 { 0x00000001 } }
impl SampleType for i32 { fn sample_format(_: Option<i32>) -> u64 { 0x00000002 } }
impl SampleType for i16 { fn sample_format(_: Option<i16>) -> u64 { 0x00000008 } }
impl SampleType for i8 { fn sample_format(_: Option<i8>) -> u64 { 0x00000010 } }
impl SampleType for u8 { fn sample_format(_: Option<u8>) -> u64 { 0x00000020 } }

fn get_sample_format<T: SampleType>() -> u64
{
    SampleType::sample_format(None::<T>)
}

pub fn get_sample_size<T: SampleType>() -> Result<uint, PaError>
{
    match unsafe { ll::Pa_GetSampleSize(get_sample_format::<T>()) }
    {
        n if n >= 0 => Ok(n as uint),
        m => to_pa_result(m).map(|_| 0),
    }
}

pub struct Stream<'a, I, O>
{
    pa_stream: *mut ll::PaStream,
    inputs: uint,
    outputs: uint,
    user_data: Box<StreamUserData<'a, I, O>>,
}

impl<'a, T: SampleType + Send> Stream<'a, T, T>
{
    pub fn open_default(num_input_channels: uint,
                        num_output_channels: uint,
                        sample_rate: f64,
                        frames_per_buffer: u64,
                        callback: Option<StreamCallback<'a, T, T>>)
                       -> Result<Stream<'a, T, T>, PaError>
    {
        unsafe
        {
            let callback_pointer = match callback
            {
                Some(_) => Some(stream_callback::<T, T>),
                None => None,
            };
            let userdata = box StreamUserData
            {
                num_input: num_input_channels,
                num_output: num_output_channels,
                callback: callback,
                finished_callback: None,
            };
            let mut pa_stream = ::std::ptr::mut_null();

            let ud_pointer: *mut c_void = mem::transmute(userdata);
            let ud_pointer_2 = ud_pointer.clone();
            let code = ll::Pa_OpenDefaultStream(&mut pa_stream as *mut *mut ll::PaStream,
                                                num_input_channels as i32,
                                                num_output_channels as i32,
                                                get_sample_format::<T>(),
                                                sample_rate,
                                                frames_per_buffer,
                                                callback_pointer,
                                                ud_pointer);
            match to_pa_result(code)
            {
                Ok(()) => Ok(Stream { pa_stream: pa_stream,
                                      user_data: mem::transmute(ud_pointer_2),
                                      inputs: num_input_channels,
                                      outputs: num_output_channels,
                             }),
                Err(v) => Err(v),
            }
        }
    }
}

impl<'a, I: SampleType + Send, O: SampleType + Send> Stream<'a, I, O>
{
    pub fn open(input: StreamParameters<I>,
                output: StreamParameters<O>,
                sample_rate: f64,
                frames_per_buffer: u64,
                flags: StreamFlags,
                callback: Option<StreamCallback<'a, I, O>>)
               -> Result<Stream<'a, I, O>, PaError>
    {
        unsafe
        {
            let callback_pointer = match callback
            {
                Some(_) => Some(stream_callback::<I, O>),
                None => None,
            };

            let user_data = box StreamUserData
            {
                num_input: input.channel_count,
                num_output: output.channel_count,
                callback: callback,
                finished_callback: None,
            };

            let mut pa_stream = ::std::ptr::mut_null();
            let ud_pointer: *mut c_void = mem::transmute(user_data);
            let ud_pointer_2 = ud_pointer.clone();

            let result = ll::Pa_OpenStream(&mut pa_stream,
                                                  &input.to_ll(),
                                                  &output.to_ll(),
                                                  sample_rate,
                                                  frames_per_buffer,
                                                  flags.bits,
                                                  callback_pointer,
                                                  ud_pointer);
            match to_pa_result(result)
            {
                Ok(()) => Ok(Stream { pa_stream: pa_stream,
                                      user_data: mem::transmute(ud_pointer_2),
                                      inputs: input.channel_count,
                                      outputs: output.channel_count,
                          }),
                Err(v) => Err(v),
            }
        }
    }

    pub fn start(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StartStream(self.pa_stream) })
    }

    pub fn stop(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_StopStream(self.pa_stream) })
    }

    pub fn abort(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_AbortStream(self.pa_stream) })
    }

    fn close(&self) -> PaResult
    {
        to_pa_result(unsafe { ll::Pa_CloseStream(self.pa_stream) })
    }

    pub fn is_stopped(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamStopped(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn is_active(&self) -> Result<bool, PaError>
    {
        match unsafe { ll::Pa_IsStreamActive(self.pa_stream) }
        {
            1 => Ok(true),
            n => to_pa_result(n).map(|_| false),
        }
    }

    pub fn num_read_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamReadAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn num_write_available(&self) -> Result<uint, PaError>
    {
        match unsafe { ll::Pa_GetStreamWriteAvailable(self.pa_stream) }
        {
            n if n >= 0 => { Ok(n as uint) },
            n => to_pa_result(n as i32).map(|_| 0),
        }
    }

    pub fn write(&self, buffer: &[O]) -> PaResult
    {
        if self.outputs == 0 { return Err(::pa::CanNotWriteToAnInputOnlyStream) }

        let pointer = buffer.as_ptr() as *const c_void;
        let frames = (buffer.len() / self.outputs) as u64;

        to_pa_result(unsafe { ll::Pa_WriteStream(self.pa_stream, pointer, frames) })
    }

    pub fn read(&self, buffer: &mut [I]) -> PaResult
    {
        if self.inputs == 0 { return Err(::pa::CanNotReadFromAnOutputOnlyStream) }

        let pointer = buffer.as_mut_ptr() as *mut c_void;
        let frames = (buffer.len() / self.inputs) as u64;

        to_pa_result(unsafe { ll::Pa_ReadStream(self.pa_stream, pointer, frames) })
    }

    pub fn cpu_load(&self) -> f64
    {
        unsafe { ll::Pa_GetStreamCpuLoad(self.pa_stream) }
    }

    pub fn time(&self) -> Duration
    {
        let time = unsafe { ll::Pa_GetStreamTime(self.pa_stream) };
        pa_time_to_duration(time)
    }

    pub fn info(&self) -> Option<StreamInfo>
    {
        unsafe
        {
            ll::Pa_GetStreamInfo(self.pa_stream)
                .to_option()
                .map(|s| StreamInfo::from_ll(s))
        }
    }

    pub fn set_finished_callback(&mut self, finished_callback: StreamFinishedCallback<'a>) -> PaResult
    {
        self.user_data.finished_callback = Some(finished_callback);
        let callback_pointer = Some(stream_finished_callback::<I, O>);
        to_pa_result(unsafe { ll::Pa_SetStreamFinishedCallback(self.pa_stream, callback_pointer) })
    }

    pub fn unset_finished_callback(&mut self) -> PaResult
    {
        self.user_data.finished_callback = None;
        to_pa_result(unsafe { ll::Pa_SetStreamFinishedCallback(self.pa_stream, None) })
    }
}

#[unsafe_destructor]
impl<'a, I: SampleType + Send, O: SampleType + Send> Drop for Stream<'a, I, O>
{
    fn drop(&mut self)
    {
        match self.close()
        {
            Err(v) => error!("Error: {}", v),
            Ok(_) => {},
        };
    }
}

pub struct StreamParameters<T>
{
    pub device: DeviceIndex,
    pub channel_count: uint,
    pub suggested_latency: Duration,
}

impl<T: SampleType> StreamParameters<T>
{
    fn to_ll(&self) -> ll::Struct_PaStreamParameters
    {
        ll::Struct_PaStreamParameters
        {
            device: self.device as i32,
            channelCount: self.channel_count as i32,
            sampleFormat: get_sample_format::<T>(),
            suggestedLatency: self.suggested_latency.num_milliseconds() as f64 / 1000.0,
            hostApiSpecificStreamInfo: ::std::ptr::mut_null(),
        }
    }
}

pub fn is_format_supported<I: SampleType, O: SampleType>(input: StreamParameters<I>, output: StreamParameters<O>, sample_rate: f64) -> PaResult
{
    to_pa_result(unsafe { ll::Pa_IsFormatSupported(&input.to_ll(), &output.to_ll(), sample_rate) })
}

pub struct StreamInfo
{
    pub input_latency: Duration,
    pub output_latency: Duration,
    pub sample_rate: f64,
}

impl StreamInfo
{
    fn from_ll(data: &ll::PaStreamInfo) -> StreamInfo
    {
        StreamInfo
        {
            input_latency: pa_time_to_duration(data.inputLatency),
            output_latency: pa_time_to_duration(data.outputLatency),
            sample_rate: data.sampleRate,
        }
    }
}

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

    // This test asserts that the sizes used by PortAudio are the same as
    // those used by Rust
    #[test]
    fn sample_sizes()
    {
        test_sample_size::<f32>();
        test_sample_size::<i32>();
        test_sample_size::<i16>();
        test_sample_size::<i8>();
        test_sample_size::<u8>();
    }

    fn test_sample_size<T: SampleType>()
    {
        use std::mem;

        let pa_size = super::get_sample_size::<T>().unwrap();
        let rs_size = mem::size_of::<T>();
        assert_eq!(rs_size, pa_size);
    }

    // In the FFI some assumptions are made as to how Some(p) and None are
    // represented when used as function pointers. This test asserts these
    // assumptions.
    #[test]
    fn option_pointer()
    {
        use std::{mem, ptr};
        use libc::c_void;

        unsafe
        {
            assert_eq!(mem::transmute::<Option<extern "C" fn()>, *const c_void>(Some(external_function)), external_function as *const c_void);
            assert_eq!(mem::transmute::<Option<extern "C" fn()>, *const c_void>(None)                   , ptr::null());
        }
    }

    extern "C" fn external_function() {}
}
<|endoftext|>