<commit_before>use std::cell::RefCell;
use std::iter::Iterator;
use std::rc::{Rc, Weak};
use std::slice::Iter;

use xml::attribute::OwnedAttribute;
use xml::common::XmlVersion;
use xml::name::OwnedName;
use xml::namespace::Namespace;

/// Describes an XML Document.
pub struct Document {
    // document version
    pub version: Option<XmlVersion>,
    // document encoding
    pub encoding: Option<String>,
    // root element
    pub root: RcElement,
}

/// Describes a node with shared ownership.
pub type RcNode = Rc<RefCell<Node>>;

/// Handy consructor for RcNodes.
#[allow(non_snake_case)]
pub fn RcNode_new(node: Node) -> RcNode {
    Rc::new(RefCell::new(node))
}

/// Describes an element with shared ownership.
pub type RcElement = Rc<RefCell<Element>>;

/// Handy constructor for RcElements.
#[allow(non_snake_case)]
pub fn RcElement_new(element: Element) -> RcElement {
    Rc::new(RefCell::new(element))
}

/// Describes a weak reference to an element.
pub type WeakElement = Weak<RefCell<Element>>;

/// Describes an element of the DOM tree.
pub struct Element {
    /// parent element
    pub parent: Option<WeakElement>,
    /// element name
    pub name: OwnedName,
    /// element attributes
    pub attributes: Vec<OwnedAttribute>,
    /// element namespace
    pub namespace: Namespace,
    /// children nodes
    children: Vec<RcNode>,
}

impl Element {

    pub fn new(parent: WeakElement, name: OwnedName, attributes: Vec<OwnedAttribute>, namespace: Namespace) -> Element {
        Element {
            parent: Some(parent),
            name: name,
            attributes: attributes,
            namespace: namespace,
            children: Vec::new(),
        }
    }

    pub fn new_root(name: OwnedName, attributes: Vec<OwnedAttribute>, namespace: Namespace) -> Element {
        Element {
            parent: None,
            name: name,
            attributes: attributes,
            namespace: namespace,
            children: Vec::new(),
        }
    }

    pub fn add_child(&mut self, node: RcNode) {
        self.children.push(node);
    }

    /// Return the number of child nodes.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Find children by name.
    pub fn find(&self, name: &str) -> Vec<RcElement> {
        self.iter_elements().filter(|elem| {
            elem.borrow().name.borrow().local_name == name
        }).collect()
    }

    /// Get the text nodes of this Element concatenated.
    pub fn text(&self) -> String {
        let mut buf = String::new();
        for text in self.iter_text() {
            buf.push_str(text.as_slice());
        }
        buf
    }

    /// Create an iterator that only yields Node::Element node types.
    pub fn iter_elements(&self) -> ElementIterator {
        ElementIterator { source: Box::new(self.children.iter()) }
    }

    // Create an iterator that only yields Node::Text node types.
    pub fn iter_text(&self) -> TextIterator {
        TextIterator { source: Box::new(self.children.iter()) }
    }

    // TODO name/namespacing
    // pub fn find<'a>(&'a self, name: &str) -> Vec<RcElement> {
    //     self.iter_elements().filter(|&elem| elem.name.borrow().local_name == name).collect()
    // }

}

/// Iterator for element nodes.
pub struct ElementIterator<'a> {
    source: Box<Iter<'a, RcNode>>,
}

impl<'a> Iterator for ElementIterator<'a> {

    type Item = RcElement;

    fn next(&mut self) -> Option<RcElement> {
        loop {
            let it = self.source.next();
            match it {
                None => return None,
                Some(node) => {
                    match *node.borrow() {
                        Node::Text(_) => continue,
                        Node::Element(ref elem) => return Some(elem.clone()),
                    }
                }
            }
        }
    }

}
/// Describes a text node of the DOM tree.
pub struct Text {
    /// parent element
    pub parent: WeakElement,
    /// the text node's content
    pub content: String,
}

impl Text {

    pub fn new(parent: WeakElement, content: String) -> Text {
        Text {
            parent: parent,
            content: content,
        }
    }

}

/// Iterator for text nodes.
pub struct TextIterator<'a> {
    source: Box<Iter<'a, RcNode>>,
}

impl<'a> Iterator for TextIterator<'a> {

    type Item = String;

    fn next(&mut self) -> Option<String> {
        loop {
            let it = self.source.next();
            match it {
                None => return None,
                Some(node) => {
                    match *node.borrow() {
                        Node::Element(_) => continue,
                        // TODO cloning the string is not ideal here.
                        Node::Text(ref text) => return Some(text.content.clone()),
                    }
                }
            }
        }
    }

}

/// Describes a node of the XML tree.
/// The node can be an element or a text node.
pub enum Node {
    Element(RcElement),
    Text(Text),
}

#[cfg(test)]
mod tests {

    use std::old_io::{MemReader};

    use builder::build;
    use super::{Document, RcElement};

    use xml::EventReader;
    use xml::common::XmlVersion;

    fn xml_to_doc(text: &str) -> Document {
        let mut reader = EventReader::new(MemReader::new(text.as_bytes().to_vec()));
        let res = build(&mut reader);
        match res {
            Ok(doc) => doc,
            Err(err) => panic!("Error: {}", err),
        }
    }

    #[test]
    fn test_find() {
        let xml = "<root><item>aa</item><item>bb</item><item>cc</item><notitem></notitem></root>";
        let doc = xml_to_doc(xml);
        let root = doc.root.borrow();

        let elems = root.find("item");
        assert_eq!(elems.len(), 3);
    }

    #[test]
    fn test_text_simple() {
        let xml = "<root>abc</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.borrow().text(), "abc");
    }

    #[test]
    fn test_test_complex() {
        let xml = "<root>abc<sep></sep>def</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.borrow().text(), "abcdef");
    }

    #[test]
    fn test_iter_elements() {
        let xml = "<root>abc<sep></sep>def<oy></oy></root>";
        let doc = xml_to_doc(xml);
        let root = doc.root.borrow();

        let it = root.iter_elements();
        let v: Vec<RcElement> = it.collect();

        assert_eq!(root.len(), 4);
        assert_eq!(v.len(), 2);
    }

    #[test]
    fn test_iter_text() {
        let xml = "<root>abc<sep></sep>def<oy></oy></root>";
        let doc = xml_to_doc(xml);
        let root = doc.root.borrow();

        let it = root.iter_text();
        let v: Vec<String> = it.collect();

        assert_eq!(root.len(), 4);
        assert_eq!(v.len(), 2);
    }

    #[test]
    fn test_version_encoding() {
        let xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><item></item></root>";
        let doc = xml_to_doc(xml);

        assert!(doc.version == Some(XmlVersion::Version10));
        assert_eq!(doc.encoding, Some("UTF-8".to_string()));
    }

}
<commit_msg>Remove unused find method.<commit_after>use std::cell::RefCell;
use std::iter::Iterator;
use std::rc::{Rc, Weak};
use std::slice::Iter;

use xml::attribute::OwnedAttribute;
use xml::common::XmlVersion;
use xml::name::OwnedName;
use xml::namespace::Namespace;

/// Describes an XML Document.
pub struct Document {
    // document version
    pub version: Option<XmlVersion>,
    // document encoding
    pub encoding: Option<String>,
    // root element
    pub root: RcElement,
}

/// Describes a node with shared ownership.
pub type RcNode = Rc<RefCell<Node>>;

/// Handy consructor for RcNodes.
#[allow(non_snake_case)]
pub fn RcNode_new(node: Node) -> RcNode {
    Rc::new(RefCell::new(node))
}

/// Describes an element with shared ownership.
pub type RcElement = Rc<RefCell<Element>>;

/// Handy constructor for RcElements.
#[allow(non_snake_case)]
pub fn RcElement_new(element: Element) -> RcElement {
    Rc::new(RefCell::new(element))
}

/// Describes a weak reference to an element.
pub type WeakElement = Weak<RefCell<Element>>;

/// Describes an element of the DOM tree.
pub struct Element {
    /// parent element
    pub parent: Option<WeakElement>,
    /// element name
    pub name: OwnedName,
    /// element attributes
    pub attributes: Vec<OwnedAttribute>,
    /// element namespace
    pub namespace: Namespace,
    /// children nodes
    children: Vec<RcNode>,
}

impl Element {

    pub fn new(parent: WeakElement, name: OwnedName, attributes: Vec<OwnedAttribute>, namespace: Namespace) -> Element {
        Element {
            parent: Some(parent),
            name: name,
            attributes: attributes,
            namespace: namespace,
            children: Vec::new(),
        }
    }

    pub fn new_root(name: OwnedName, attributes: Vec<OwnedAttribute>, namespace: Namespace) -> Element {
        Element {
            parent: None,
            name: name,
            attributes: attributes,
            namespace: namespace,
            children: Vec::new(),
        }
    }

    pub fn add_child(&mut self, node: RcNode) {
        self.children.push(node);
    }

    /// Return the number of child nodes.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Find children by name.
    /// Currently ignores namespaces.
    // TODO namespacing
    pub fn find(&self, name: &str) -> Vec<RcElement> {
        self.iter_elements().filter(|elem| {
            elem.borrow().name.borrow().local_name == name
        }).collect()
    }

    /// Get the text nodes of this Element concatenated.
    pub fn text(&self) -> String {
        let mut buf = String::new();
        for text in self.iter_text() {
            buf.push_str(text.as_slice());
        }
        buf
    }

    /// Create an iterator that only yields Node::Element node types.
    pub fn iter_elements(&self) -> ElementIterator {
        ElementIterator { source: Box::new(self.children.iter()) }
    }

    // Create an iterator that only yields Node::Text node types.
    pub fn iter_text(&self) -> TextIterator {
        TextIterator { source: Box::new(self.children.iter()) }
    }

}

/// Iterator for element nodes.
pub struct ElementIterator<'a> {
    source: Box<Iter<'a, RcNode>>,
}

impl<'a> Iterator for ElementIterator<'a> {

    type Item = RcElement;

    fn next(&mut self) -> Option<RcElement> {
        loop {
            let it = self.source.next();
            match it {
                None => return None,
                Some(node) => {
                    match *node.borrow() {
                        Node::Text(_) => continue,
                        Node::Element(ref elem) => return Some(elem.clone()),
                    }
                }
            }
        }
    }

}
/// Describes a text node of the DOM tree.
pub struct Text {
    /// parent element
    pub parent: WeakElement,
    /// the text node's content
    pub content: String,
}

impl Text {

    pub fn new(parent: WeakElement, content: String) -> Text {
        Text {
            parent: parent,
            content: content,
        }
    }

}

/// Iterator for text nodes.
pub struct TextIterator<'a> {
    source: Box<Iter<'a, RcNode>>,
}

impl<'a> Iterator for TextIterator<'a> {

    type Item = String;

    fn next(&mut self) -> Option<String> {
        loop {
            let it = self.source.next();
            match it {
                None => return None,
                Some(node) => {
                    match *node.borrow() {
                        Node::Element(_) => continue,
                        // TODO cloning the string is not ideal here.
                        Node::Text(ref text) => return Some(text.content.clone()),
                    }
                }
            }
        }
    }

}

/// Describes a node of the XML tree.
/// The node can be an element or a text node.
pub enum Node {
    Element(RcElement),
    Text(Text),
}

#[cfg(test)]
mod tests {

    use std::old_io::{MemReader};

    use builder::build;
    use super::{Document, RcElement};

    use xml::EventReader;
    use xml::common::XmlVersion;

    fn xml_to_doc(text: &str) -> Document {
        let mut reader = EventReader::new(MemReader::new(text.as_bytes().to_vec()));
        let res = build(&mut reader);
        match res {
            Ok(doc) => doc,
            Err(err) => panic!("Error: {}", err),
        }
    }

    #[test]
    fn test_find() {
        let xml = "<root><item>aa</item><item>bb</item><item>cc</item><notitem></notitem></root>";
        let doc = xml_to_doc(xml);
        let root = doc.root.borrow();

        let elems = root.find("item");
        assert_eq!(elems.len(), 3);
    }

    #[test]
    fn test_text_simple() {
        let xml = "<root>abc</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.borrow().text(), "abc");
    }

    #[test]
    fn test_test_complex() {
        let xml = "<root>abc<sep></sep>def</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.borrow().text(), "abcdef");
    }

    #[test]
    fn test_iter_elements() {
        let xml = "<root>abc<sep></sep>def<oy></oy></root>";
        let doc = xml_to_doc(xml);
        let root = doc.root.borrow();

        let it = root.iter_elements();
        let v: Vec<RcElement> = it.collect();

        assert_eq!(root.len(), 4);
        assert_eq!(v.len(), 2);
    }

    #[test]
    fn test_iter_text() {
        let xml = "<root>abc<sep></sep>def<oy></oy></root>";
        let doc = xml_to_doc(xml);
        let root = doc.root.borrow();

        let it = root.iter_text();
        let v: Vec<String> = it.collect();

        assert_eq!(root.len(), 4);
        assert_eq!(v.len(), 2);
    }

    #[test]
    fn test_version_encoding() {
        let xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><item></item></root>";
        let doc = xml_to_doc(xml);

        assert!(doc.version == Some(XmlVersion::Version10));
        assert_eq!(doc.encoding, Some("UTF-8".to_string()));
    }

}
<|endoftext|>


<commit_before>// $ cargo bench --features full --bench file

#![recursion_limit = "256"]
#![feature(rustc_private, test)]

extern crate test;

#[macro_use]
#[path = "../tests/macros/mod.rs"]
mod macros;

#[path = "../tests/common/mod.rs"]
mod common;

use test::Bencher;
use proc_macro2::TokenStream;
use std::fs;
use std::str::FromStr;

const FILE: &str = "tests/rust/src/libcore/str/mod.rs";

#[bench]
fn parse_file(b: &mut Bencher) {
    common::clone_rust();
    let content = fs::read_to_string(FILE).unwrap();
    let tokens = TokenStream::from_str(&content).unwrap();
    b.iter(|| syn::parse2::<syn::File>(tokens.clone()));
}
<commit_msg>Format with rustfmt 2019-06-09<commit_after>// $ cargo bench --features full --bench file

#![recursion_limit = "256"]
#![feature(rustc_private, test)]

extern crate test;

#[macro_use]
#[path = "../tests/macros/mod.rs"]
mod macros;

#[path = "../tests/common/mod.rs"]
mod common;

use proc_macro2::TokenStream;
use std::fs;
use std::str::FromStr;
use test::Bencher;

const FILE: &str = "tests/rust/src/libcore/str/mod.rs";

#[bench]
fn parse_file(b: &mut Bencher) {
    common::clone_rust();
    let content = fs::read_to_string(FILE).unwrap();
    let tokens = TokenStream::from_str(&content).unwrap();
    b.iter(|| syn::parse2::<syn::File>(tokens.clone()));
}
<|endoftext|>


<commit_before>//#![feature(trace_macros)]
#![feature(test)]
extern crate test;
#[macro_use]
extern crate cookie_factory;

use std::str;
use std::iter::repeat;
use std::collections::HashMap;

use cookie_factory::*;
use test::Bencher;

#[derive(Clone, Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

pub fn gen_json_value<'a>(x:(&'a mut [u8],usize), g:&JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  match g {
    JsonValue::Str(ref s) => gen_str(x, s),
    JsonValue::Boolean(b) => gen_bool(x, b),
    JsonValue::Num(ref f) => gen_num(x, f),
    JsonValue::Array(ref v) => gen_array(x, v),
    JsonValue::Object(ref o) => gen_object(x, o),
  }
}

pub fn gen_str<'a>(x:(&'a mut [u8],usize), s:&String) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b"\""[..]) >>
    gen_slice!(s.as_bytes()) >>
    gen_slice!(&b"\""[..])
  )
}

pub fn gen_bool<'a>(x:(&'a mut [u8],usize), b:&bool) -> Result<(&'a mut [u8],usize),GenError> {
  let sl = match b {
    true => &b"true"[..],
    false => &b"false"[..],
  };

  gen_slice!(x, sl)
}

pub fn gen_num<'a>(x:(&'a mut [u8],usize), b:&f64) -> Result<(&'a mut [u8],usize),GenError> {
  //TODO
  gen_slice!(x, &b"1234.56"[..])
}

pub fn gen_array<'a>(x:(&'a mut [u8],usize), arr:&[JsonValue]) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"["[..])?;
  if arr.len() > 0 {
    output = gen_json_value(output, &arr[0])?;

    if arr.len() > 1 {
      output = gen_many!((output.0, output.1),
        &arr[1..],
        gen_array_element
      )?;
    }
  }
  gen_slice!(output, &b"]"[..])
}

pub fn gen_array_element<'a>(x:(&'a mut [u8],usize), val: &JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b","[..]) >>
    gen_call!(gen_json_value, val)
  )
}

pub fn gen_object<'a>(x:(&'a mut [u8],usize), o:&HashMap<String, JsonValue>) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"{"[..])?;
  let mut it = o.iter();

  if let Some((key, value)) = it.next() {
    output = gen_object_element(output, key, value, true)?;
  }

  for (key, value) in it {
    output = gen_object_element(output, key, value, false)?;
  }

  gen_slice!(output, &b"]"[..])
}

pub fn gen_object_element<'a>(x:(&'a mut [u8],usize), key: &String, value:&JsonValue, is_first: bool) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = x;
  if !is_first {
    output = gen_slice!(output, &b","[..])?;
  }

  do_gen!(output,
    gen_call!(gen_str, key) >>
    gen_slice!(&b":"[..]) >>
    gen_call!(gen_json_value, value)
  )
}
/*
named!(float<f32>, flat_map!(recognize_float, parse_to!(f32)));

//FIXME: verify how json strings are formatted
named!(
  string<&str>,
  delimited!(
    char!('\"'),
    map_res!(
      escaped!(call!(alphanumeric), '\\', one_of!("\"n\\")),
      str::from_utf8
    ),
    //map_res!(escaped!(take_while1!(is_alphanumeric), '\\', one_of!("\"n\\")), str::from_utf8),
    char!('\"')
  )
);

named!(
  boolean<bool>,
  alt!(value!(false, tag!("false")) | value!(true, tag!("true")))
);

named!(
  array<Vec<JsonValue>>,
  ws!(delimited!(
    char!('['),
    separated_list!(char!(','), value),
    char!(']')
  ))
);

named!(
  key_value<(&str, JsonValue)>,
  ws!(separated_pair!(string, char!(':'), value))
);

named!(
  hash<HashMap<String, JsonValue>>,
  ws!(map!(
    delimited!(
      char!('{'),
      separated_list!(char!(','), key_value),
      char!('}')
    ),
    |tuple_vec| tuple_vec
      .into_iter()
      .map(|(k, v)| (String::from(k), v))
      .collect()
  ))
);

named!(
  value<JsonValue>,
  ws!(alt!(
      hash    => { |h| JsonValue::Object(h)            } |
      array   => { |v| JsonValue::Array(v)             } |
      string  => { |s| JsonValue::Str(String::from(s)) } |
      float   => { |f| JsonValue::Num(f)               } |
      boolean => { |b| JsonValue::Boolean(b)           }
    ))
);
*/

// from https://github.com/bluss/maplit
macro_rules! hashmap {
    (@single $($x:tt)*) => (());
    (@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));

    ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let _cap = hashmap!(@count $($key),*);
            let mut _map = ::std::collections::HashMap::with_capacity(_cap);
            $(
                let _ = _map.insert($key, $value);
            )*
            _map
        }
    };
}

#[bench]
fn json_bench(b: &mut Bencher) {
  let element = JsonValue::Object(hashmap!{
    String::from("arr") => JsonValue::Array(vec![JsonValue::Num(1.0), JsonValue::Num(12.3), JsonValue::Num(42.0)]),
    String::from("b") => JsonValue::Boolean(true),
    String::from("o") => JsonValue::Object(hashmap!{
      String::from("x") => JsonValue::Str(String::from("abcd")),
      String::from("y") => JsonValue::Str(String::from("efgh")),
      String::from("empty") => JsonValue::Array(vec![]),
    }),
  });

  let value = JsonValue::Array(repeat(element).take(10).collect::<Vec<JsonValue>>());

  let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();
  let ptr = {
    let (buf, index) = gen_json_value((&mut buffer, 0), &value).unwrap();

    println!("result:\n{}", str::from_utf8(buf).unwrap());
    //panic!();

    buf.as_ptr() as u64
  };

  b.bytes = ptr - (&buffer).as_ptr() as u64;
  b.iter(|| {
    let res = gen_json_value((&mut buffer, 0), &value).unwrap();
    res.1
  });
}

<commit_msg>fix bytes calcluations in bench<commit_after>//#![feature(trace_macros)]
#![feature(test)]
extern crate test;
#[macro_use]
extern crate cookie_factory;

use std::str;
use std::iter::repeat;
use std::collections::HashMap;

use cookie_factory::*;
use test::Bencher;

#[derive(Clone, Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

pub fn gen_json_value<'a>(x:(&'a mut [u8],usize), g:&JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  match g {
    JsonValue::Str(ref s) => gen_str(x, s),
    JsonValue::Boolean(b) => gen_bool(x, b),
    JsonValue::Num(ref f) => gen_num(x, f),
    JsonValue::Array(ref v) => gen_array(x, v),
    JsonValue::Object(ref o) => gen_object(x, o),
  }
}

pub fn gen_str<'a>(x:(&'a mut [u8],usize), s:&String) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b"\""[..]) >>
    gen_slice!(s.as_bytes()) >>
    gen_slice!(&b"\""[..])
  )
}

pub fn gen_bool<'a>(x:(&'a mut [u8],usize), b:&bool) -> Result<(&'a mut [u8],usize),GenError> {
  let sl = match b {
    true => &b"true"[..],
    false => &b"false"[..],
  };

  gen_slice!(x, sl)
}

pub fn gen_num<'a>(x:(&'a mut [u8],usize), b:&f64) -> Result<(&'a mut [u8],usize),GenError> {
  //TODO
  gen_slice!(x, &b"1234.56"[..])
}

pub fn gen_array<'a>(x:(&'a mut [u8],usize), arr:&[JsonValue]) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"["[..])?;
  if arr.len() > 0 {
    output = gen_json_value(output, &arr[0])?;

    if arr.len() > 1 {
      output = gen_many!((output.0, output.1),
        &arr[1..],
        gen_array_element
      )?;
    }
  }
  gen_slice!(output, &b"]"[..])
}

pub fn gen_array_element<'a>(x:(&'a mut [u8],usize), val: &JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b","[..]) >>
    gen_call!(gen_json_value, val)
  )
}

pub fn gen_object<'a>(x:(&'a mut [u8],usize), o:&HashMap<String, JsonValue>) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"{"[..])?;
  let mut it = o.iter();

  if let Some((key, value)) = it.next() {
    output = gen_object_element(output, key, value, true)?;
  }

  for (key, value) in it {
    output = gen_object_element(output, key, value, false)?;
  }

  gen_slice!(output, &b"]"[..])
}

pub fn gen_object_element<'a>(x:(&'a mut [u8],usize), key: &String, value:&JsonValue, is_first: bool) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = x;
  if !is_first {
    output = gen_slice!(output, &b","[..])?;
  }

  do_gen!(output,
    gen_call!(gen_str, key) >>
    gen_slice!(&b":"[..]) >>
    gen_call!(gen_json_value, value)
  )
}
/*
named!(float<f32>, flat_map!(recognize_float, parse_to!(f32)));

//FIXME: verify how json strings are formatted
named!(
  string<&str>,
  delimited!(
    char!('\"'),
    map_res!(
      escaped!(call!(alphanumeric), '\\', one_of!("\"n\\")),
      str::from_utf8
    ),
    //map_res!(escaped!(take_while1!(is_alphanumeric), '\\', one_of!("\"n\\")), str::from_utf8),
    char!('\"')
  )
);

named!(
  boolean<bool>,
  alt!(value!(false, tag!("false")) | value!(true, tag!("true")))
);

named!(
  array<Vec<JsonValue>>,
  ws!(delimited!(
    char!('['),
    separated_list!(char!(','), value),
    char!(']')
  ))
);

named!(
  key_value<(&str, JsonValue)>,
  ws!(separated_pair!(string, char!(':'), value))
);

named!(
  hash<HashMap<String, JsonValue>>,
  ws!(map!(
    delimited!(
      char!('{'),
      separated_list!(char!(','), key_value),
      char!('}')
    ),
    |tuple_vec| tuple_vec
      .into_iter()
      .map(|(k, v)| (String::from(k), v))
      .collect()
  ))
);

named!(
  value<JsonValue>,
  ws!(alt!(
      hash    => { |h| JsonValue::Object(h)            } |
      array   => { |v| JsonValue::Array(v)             } |
      string  => { |s| JsonValue::Str(String::from(s)) } |
      float   => { |f| JsonValue::Num(f)               } |
      boolean => { |b| JsonValue::Boolean(b)           }
    ))
);
*/

// from https://github.com/bluss/maplit
macro_rules! hashmap {
    (@single $($x:tt)*) => (());
    (@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));

    ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let _cap = hashmap!(@count $($key),*);
            let mut _map = ::std::collections::HashMap::with_capacity(_cap);
            $(
                let _ = _map.insert($key, $value);
            )*
            _map
        }
    };
}

#[bench]
fn json_bench(b: &mut Bencher) {
  let element = JsonValue::Object(hashmap!{
    String::from("arr") => JsonValue::Array(vec![JsonValue::Num(1.0), JsonValue::Num(12.3), JsonValue::Num(42.0)]),
    String::from("b") => JsonValue::Boolean(true),
    String::from("o") => JsonValue::Object(hashmap!{
      String::from("x") => JsonValue::Str(String::from("abcd")),
      String::from("y") => JsonValue::Str(String::from("efgh")),
      String::from("empty") => JsonValue::Array(vec![]),
    }),
  });

  let value = JsonValue::Array(repeat(element).take(10).collect::<Vec<JsonValue>>());

  let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();
  let index = {
    let (buf, index) = gen_json_value((&mut buffer, 0), &value).unwrap();

    println!("result:\n{}", str::from_utf8(buf).unwrap());
    //panic!();

    index as u64
  };

  println!("wrote {} bytes", index);
  b.bytes = index;
  b.iter(|| {
    let res = gen_json_value((&mut buffer, 0), &value).unwrap();
    res.1
  });
}

<|endoftext|>


<commit_before>#![feature(test)]
extern crate combine as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Consumed, Parser, ParseError, ParseResult, State, Stream, BufferedStream};
use pc::combinator::{any, between, choice, many, many1, optional, parser, satisfy, sep_by, Expected,
                     FnParser, Skip};
use pc::char::{char, digit, spaces, Spaces, string};
use pc::from_iter;

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>),
}

fn lex<P>(p: P) -> Skip<P, Spaces<P::Input>>
    where P: Parser,
          P::Input: Stream<Item = char>
{
    p.skip(spaces())
}
struct Json<I>(::std::marker::PhantomData<fn(I) -> I>);

type FnPtrParser<O, I> = FnParser<I, fn(I) -> ParseResult<O, I>>;
type JsonParser<O, I> = Expected<FnPtrParser<O, I>>;

fn fn_parser<O, I>(f: fn(I) -> ParseResult<O, I>, err: &'static str) -> JsonParser<O, I>
    where I: Stream<Item = char>
{
    parser(f).expected(err)
}

impl<I> Json<I>
    where I: Stream<Item = char>
{
    fn integer() -> JsonParser<i64, I> {
        fn_parser(Json::<I>::integer_, "integer")
    }
    fn integer_(input: I) -> ParseResult<i64, I> {
        let (s, input) = try!(lex(many1::<String, _>(digit())).parse_lazy(input).into());
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number() -> JsonParser<f64, I> {
        fn_parser(Json::<I>::number_, "number")
    }
    fn number_(input: I) -> ParseResult<f64, I> {
        let i = char('0')
            .map(|_| 0.0)
            .or(Json::<I>::integer().map(|x| x as f64));
        let fractional = many(digit()).map(|digits: String| {
            let mut magnitude = 1.0;
            digits.chars().fold(0.0, |acc, d| {
                magnitude /= 10.0;
                match d.to_digit(10) {
                    Some(d) => acc + (d as f64) * magnitude,
                    None => panic!("Not a digit"),
                }
            })
        });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(Json::<I>::integer()));
        lex(optional(char('-'))
                .and(i)
                .map(|(sign, n)| if sign.is_some() { -n } else { n })
                .and(optional(char('.')).with(fractional))
                .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
                .and(optional(exp))
                .map(|(n, exp_option)| match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n,
                }))
            .parse_lazy(input)
            .into()
    }

    fn char() -> JsonParser<char, I> {
        fn_parser(Json::<I>::char_, "char")
    }
    fn char_(input: I) -> ParseResult<char, I> {
        let (c, input) = try!(any().parse_lazy(input).into());
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().any(|x| x == c)).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c,//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_stream(input)),
            '"' => {
                Err(Consumed::Empty(ParseError::from_errors(input.into_inner().position(),
                                                            Vec::new())))
            }
            _ => Ok((c, input)),
        }
    }
    fn string() -> JsonParser<String, I> {
        fn_parser(Json::<I>::string_, "string")
    }
    fn string_(input: I) -> ParseResult<String, I> {
        between(char('"'), lex(char('"')), many(Json::<I>::char())).parse_lazy(input).into()
    }

    fn object() -> JsonParser<Value, I> {
        fn_parser(Json::<I>::object_, "object")
    }
    fn object_(input: I) -> ParseResult<Value, I> {
        let field = (Json::<I>::string(), lex(char(':')), Json::<I>::value()).map(|t| (t.0, t.2));
        let fields = sep_by(field, lex(char(',')));
        between(lex(char('{')), lex(char('}')), fields)
            .map(Value::Object)
            .parse_lazy(input)
            .into()
    }

    fn value() -> FnPtrParser<Value, I> {
        parser(Json::<I>::value_ as fn(_) -> _)
    }
    #[allow(unconditional_recursion)]
    fn value_(input: I) -> ParseResult<Value, I> {
        let mut array = between(lex(char('[')),
                                lex(char(']')),
                                sep_by(Json::<I>::value(), lex(char(','))))
            .map(Value::Array);

        choice::<[&mut Parser<Input = I, Output = Value>; 7],
                 _>([&mut Json::<I>::string().map(Value::String),
                     &mut Json::<I>::object(),
                     &mut array,
                     &mut Json::<I>::number().map(Value::Number),
                     &mut lex(string("false").map(|_| Value::Bool(false))),
                     &mut lex(string("true").map(|_| Value::Bool(true))),
                     &mut lex(string("null").map(|_| Value::Null))])
            .parse_lazy(input)
            .into()
    }
}

#[test]
fn json_test() {
    use self::Value::*;
    let input = r#"{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = Json::value().parse(input);
    let expected = Object(vec![("array", Array(vec![Number(1.0), String("".to_string())])),
                               ("object", Object(HashMap::new())),
                               ("number", Number(3.14)),
                               ("int", Number(-100.)),
                               ("exp", Number(-1e2)),
                               ("exp_neg", Number(23E-2)),
                               ("true", Bool(true)),
                               ("false", Bool(false)),
                               ("null", Null)]
        .into_iter()
        .map(|(k, v)| (k.to_string(), v))
        .collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = Json::value();
    match parser.parse(State::new(&data[..])) {
        Ok((Value::Array(_), _)) => (),
        Ok(_) => assert!(false),
        Err(err) => {
            println!("{}", err);
            assert!(false);
        }
    }
    bencher.iter(|| {
        let result = parser.parse(State::new(&data[..]));
        ::test::black_box(result)
    });
}

#[bench]
fn bench_buffered_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    bencher.iter(|| {
        let buffer = BufferedStream::new(from_iter(data.chars()), 1);
        let mut parser = Json::value();
        match parser.parse(State::new(buffer.as_stream())) {
            Ok((Value::Array(v), _)) => {
                ::test::black_box(v);
            }
            Ok(_) => assert!(false),
            Err(err) => {
                println!("{}", err);
                assert!(false);
            }
        }
    });
}
<commit_msg>Fix a bug that causes wrong evaluation in number between 0.0 and 1.0<commit_after>#![feature(test)]
extern crate combine as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Consumed, Parser, ParseError, ParseResult, State, Stream, BufferedStream};
use pc::combinator::{any, between, choice, many, many1, optional, parser, satisfy, sep_by, Expected,
                     FnParser, Skip};
use pc::char::{char, digit, spaces, Spaces, string};
use pc::from_iter;

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>),
}

fn lex<P>(p: P) -> Skip<P, Spaces<P::Input>>
    where P: Parser,
          P::Input: Stream<Item = char>
{
    p.skip(spaces())
}
struct Json<I>(::std::marker::PhantomData<fn(I) -> I>);

type FnPtrParser<O, I> = FnParser<I, fn(I) -> ParseResult<O, I>>;
type JsonParser<O, I> = Expected<FnPtrParser<O, I>>;

fn fn_parser<O, I>(f: fn(I) -> ParseResult<O, I>, err: &'static str) -> JsonParser<O, I>
    where I: Stream<Item = char>
{
    parser(f).expected(err)
}

impl<I> Json<I>
    where I: Stream<Item = char>
{
    fn integer() -> JsonParser<i64, I> {
        fn_parser(Json::<I>::integer_, "integer")
    }
    fn integer_(input: I) -> ParseResult<i64, I> {
        let (s, input) = try!(lex(many1::<String, _>(digit())).parse_lazy(input).into());
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number() -> JsonParser<f64, I> {
        fn_parser(Json::<I>::number_, "number")
    }
    fn number_(input: I) -> ParseResult<f64, I> {
        let i = char('0')
            .map(|_| 0.0)
            .or(Json::<I>::integer().map(|x| x as f64));
        let fractional = many(digit()).map(|digits: String| {
            let mut magnitude = 1.0;
            digits.chars().fold(0.0, |acc, d| {
                magnitude /= 10.0;
                match d.to_digit(10) {
                    Some(d) => acc + (d as f64) * magnitude,
                    None => panic!("Not a digit"),
                }
            })
        });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(Json::<I>::integer()));
        lex(optional(char('-'))
                .and(i)
                .map(|(sign, n)| if sign.is_some() { -n } else { n })
                .and(optional(char('.')).with(fractional))
                .map(|(x, y)| if x >= 0.0 { x + y } else { x - y })
                .and(optional(exp))
                .map(|(n, exp_option)| match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n,
                }))
            .parse_lazy(input)
            .into()
    }

    fn char() -> JsonParser<char, I> {
        fn_parser(Json::<I>::char_, "char")
    }
    fn char_(input: I) -> ParseResult<char, I> {
        let (c, input) = try!(any().parse_lazy(input).into());
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().any(|x| x == c)).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c,//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_stream(input)),
            '"' => {
                Err(Consumed::Empty(ParseError::from_errors(input.into_inner().position(),
                                                            Vec::new())))
            }
            _ => Ok((c, input)),
        }
    }
    fn string() -> JsonParser<String, I> {
        fn_parser(Json::<I>::string_, "string")
    }
    fn string_(input: I) -> ParseResult<String, I> {
        between(char('"'), lex(char('"')), many(Json::<I>::char())).parse_lazy(input).into()
    }

    fn object() -> JsonParser<Value, I> {
        fn_parser(Json::<I>::object_, "object")
    }
    fn object_(input: I) -> ParseResult<Value, I> {
        let field = (Json::<I>::string(), lex(char(':')), Json::<I>::value()).map(|t| (t.0, t.2));
        let fields = sep_by(field, lex(char(',')));
        between(lex(char('{')), lex(char('}')), fields)
            .map(Value::Object)
            .parse_lazy(input)
            .into()
    }

    fn value() -> FnPtrParser<Value, I> {
        parser(Json::<I>::value_ as fn(_) -> _)
    }
    #[allow(unconditional_recursion)]
    fn value_(input: I) -> ParseResult<Value, I> {
        let mut array = between(lex(char('[')),
                                lex(char(']')),
                                sep_by(Json::<I>::value(), lex(char(','))))
            .map(Value::Array);

        choice::<[&mut Parser<Input = I, Output = Value>; 7],
                 _>([&mut Json::<I>::string().map(Value::String),
                     &mut Json::<I>::object(),
                     &mut array,
                     &mut Json::<I>::number().map(Value::Number),
                     &mut lex(string("false").map(|_| Value::Bool(false))),
                     &mut lex(string("true").map(|_| Value::Bool(true))),
                     &mut lex(string("null").map(|_| Value::Null))])
            .parse_lazy(input)
            .into()
    }
}

#[test]
fn json_test() {
    use self::Value::*;
    let input = r#"{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "small_number": 0.59,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = Json::value().parse(input);
    let expected = Object(vec![("array", Array(vec![Number(1.0), String("".to_string())])),
                               ("object", Object(HashMap::new())),
                               ("number", Number(3.14)),
                               ("small_number", Number(0.59)),
                               ("int", Number(-100.)),
                               ("exp", Number(-1e2)),
                               ("exp_neg", Number(23E-2)),
                               ("true", Bool(true)),
                               ("false", Bool(false)),
                               ("null", Null)]
        .into_iter()
        .map(|(k, v)| (k.to_string(), v))
        .collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = Json::value();
    match parser.parse(State::new(&data[..])) {
        Ok((Value::Array(_), _)) => (),
        Ok(_) => assert!(false),
        Err(err) => {
            println!("{}", err);
            assert!(false);
        }
    }
    bencher.iter(|| {
        let result = parser.parse(State::new(&data[..]));
        ::test::black_box(result)
    });
}

#[bench]
fn bench_buffered_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    bencher.iter(|| {
        let buffer = BufferedStream::new(from_iter(data.chars()), 1);
        let mut parser = Json::value();
        match parser.parse(State::new(buffer.as_stream())) {
            Ok((Value::Array(v), _)) => {
                ::test::black_box(v);
            }
            Ok(_) => assert!(false),
            Err(err) => {
                println!("{}", err);
                assert!(false);
            }
        }
    });
}
<|endoftext|>


<commit_before>//! Types around a convolution, see also https://en.wikipedia.org/wiki/Convolution.
//!
//! Convolutions in this library can be defined in time or frequency domain. In
//! frequency domain the convolution is automatically transformed into a multiplication
//! which is the analog operation to a convolution in time domain.
use RealNumber;
use num::traits::Zero;
use num::complex::{Complex, Complex32,Complex64};
use vector_types::{
    RealTimeVector,
    ComplexTimeVector,
    ComplexFreqVector
};
use vector_types::definitions::{
    DataVector,
    RealVectorOperations,
    ComplexVectorOperations
};

use vector_types::time_freq_impl::{
    TimeDomainOperations,
    FrequencyDomainOperations
};

/// A convolution function in time domain and real number space
pub trait RealTimeConvFunction<T>
    where T: RealNumber {
    /// Calculates the convolution for a real data point
    fn calc(&self, x: T) -> T;
}

/// A convolution function in time domain and complex number space
pub trait ComplexTimeConvFunction<T>
    where T: RealNumber {
    /// Calculates the convolution for a real data point
    fn calc(&self, x: T) -> Complex<T>;
}

/// A convolution function in frequency domain and complex number space
pub trait ComplexFrequencyConvFunction<T>
    where T: RealNumber {
    /// Calculates the convolution for a real data point
    fn calc(&self, x: T) -> Complex<T>;
}

/// Allows to create a lookup table with linear interpolation between table points.
/// This usually speeds up a convolution and sacrifies accuracy.
pub struct RealTimeLinearTableLookup<T>
    where T: RealNumber {
    table: Vec<T>,
    delta: T,
    offset: T
}

/// Allows to create a lookup table with linear interpolation between table points.
/// This usually speeds up a convolution and sacrifies accuracy.
pub struct ComplexTimeLinearTableLookup<T>
    where T: RealNumber {
    table: Vec<Complex<T>>,
    delta: T,
    offset: T
}

/// Allows to create a lookup table with linear interpolation between table points.
/// This usually speeds up a convolution and sacrifies accuracy.
pub struct ComplexFrequencyLinearTableLookup<T>
    where T: RealNumber {
    table: Vec<Complex<T>>,
    delta: T,
    offset: T
}

macro_rules! add_linear_table_lookup_impl {
    ($($name: ident: $conv_type: ident, $($data_type: ident, $result_type:ident),*);*) => {
        $(
            $(
                impl $conv_type<$data_type> for $name<$data_type> {
                    fn calc(&self, x: $data_type) -> $result_type {
                        let len = self.table.len();
                        let center = len / 2;
                        let center_float = center as $data_type;
                        let x = x / self.delta - self.offset + center_float;
                        let round_float = x.round();
                        let round = round_float as usize;
                        if round >= len {
                            return $result_type::zero();
                        }

                        let round_tolerance = 1e-6;
                        if (x - round_float).abs() < round_tolerance {
                            return self.table[round];
                        }

                        if x > round_float {
                            let other = round + 1;
                            if other >= len {
                                return self.table[round];
                            }
                            let y0 = self.table[round];
                            let x0 = round_float;
                            let y1 = self.table[other];
                            return y0 + (y1 - y0) * (x - x0);
                        } else {
                            if round == 0 {
                                return self.table[round];
                            }
                            let other = round - 1;
                            let y0 = self.table[round];
                            let x0 = round_float;
                            let y1 = self.table[other];
                            return y0 + (y1 - y0) * (x0 - x);
                        }
                    }
                }

                impl $name<$data_type> {
                    /// Creates a lookup table by putting the pieces together.
                    pub fn from_raw_parts(table: &[$result_type], delta: $data_type, offset: $data_type) -> Self {
                        let owned_table = Vec::from(table);
                        $name { table: owned_table, delta: delta, offset: offset }
                    }

                    /// Creates a lookup table from another convolution function. The `delta` argument
                    /// can be used to balance performance vs. accuracy.
                    pub fn from_conv_function(other: &$conv_type<$data_type>, delta: $data_type, offset: $data_type, len: usize) -> Self {
                        let center = (len / 2) as isize;
                        let mut table = vec![$result_type::zero(); len];
                        let mut i = -center;
                        for n in &mut table {
                            *n = other.calc((i as $data_type) * delta);
                            i += 1;
                        }
                        $name { table: table, delta: delta, offset: offset }
                    }
                }
            )*
        )*
    }
}
add_linear_table_lookup_impl!(
    RealTimeLinearTableLookup: RealTimeConvFunction, f32, f32, f64, f64;
    ComplexTimeLinearTableLookup: ComplexTimeConvFunction, f32, Complex32, f64, Complex64;
    ComplexFrequencyLinearTableLookup: ComplexFrequencyConvFunction, f32, Complex32, f64, Complex64);

macro_rules! add_real_time_linear_table_impl {
    ($($data_type: ident),*) => {
        $(
            impl RealTimeLinearTableLookup<$data_type> {
                /// Convert the lookup table into complex number space
                pub fn to_complex(&self) -> ComplexTimeLinearTableLookup<$data_type> {
                    let vector = RealTimeVector::from_array(&self.table);
                    let complex = vector.to_complex().expect("to_complex shouldn't fail");
                    let complex = complex.complex_data();
                    let mut table = Vec::with_capacity(complex.len());
                    for n in complex {
                        table.push(*n);
                    }
                    ComplexTimeLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }
            }
        )*
    }
}
add_real_time_linear_table_impl!(f32, f64);

macro_rules! add_complex_time_linear_table_impl {
    ($($data_type: ident),*) => {
        $(
            impl ComplexTimeLinearTableLookup<$data_type> {
                /// Convert the lookup table into real number space
                pub fn to_real(self) -> RealTimeLinearTableLookup<$data_type> {
                    let vector = ComplexTimeVector::from_complex(&self.table);
                    let real = vector.to_real().expect("to_complex shouldn't fail");
                    let real = real.data();
                    let mut table = Vec::with_capacity(real.len());
                    for n in real {
                        table.push(*n);
                    }
                    RealTimeLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }

                /// Convert the lookup table into frequency domain
                pub fn fft(self) -> ComplexFrequencyLinearTableLookup<$data_type> {
                    let vector = ComplexTimeVector::from_complex(&self.table);
                    let freq = vector.fft().expect("vector fft shouldn't fail");
                    let freq = freq.complex_data();
                    let mut table = Vec::with_capacity(freq.len());
                    for n in freq {
                        table.push(*n);
                    }
                    ComplexFrequencyLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }
            }
        )*
    }
}
add_complex_time_linear_table_impl!(f32, f64);

macro_rules! add_complex_frequency_linear_table_impl {
    ($($data_type: ident),*) => {
        $(
            impl ComplexFrequencyLinearTableLookup<$data_type> {

                /// Convert the lookup table into time domain
                pub fn ifft(self) -> ComplexTimeLinearTableLookup<$data_type> {
                    let vector = ComplexFreqVector::from_complex(&self.table);
                    let time = vector.ifft().expect("vector ifft shouldn't fail");
                    let time = time.complex_data();
                    let mut table = Vec::with_capacity(time.len());
                    for n in time {
                        table.push(*n);
                    }
                    ComplexTimeLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }
            }
        )*
    }
}
add_complex_frequency_linear_table_impl!(f32, f64);

/// Raised cosine function according to https://en.wikipedia.org/wiki/Raised-cosine_filter
pub struct  RaiseCosineFuncton<T>
    where T: RealNumber {
    rolloff: T
}

impl<T> RealTimeConvFunction<T> for RaiseCosineFuncton<T>
    where T: RealNumber {
    fn calc(&self, x: T) -> T {
        if x == T::zero() {
            return T::one();
        }

        let one = T::one();
        let two = T::from(2.0).unwrap();
        let pi = two * one.asin();
        let four = two * two;
        if x.abs() == one / (two * self.rolloff) {
            let arg = pi / two / self.rolloff;
            return (arg).sin() / arg * pi / four;
        }

        let pi_x = pi * x;
        let arg = two * self.rolloff * x;
        return pi_x.sin() * (pi_x * self.rolloff).cos() / pi_x / (one - (arg * arg))
    }
}

impl<T> RaiseCosineFuncton<T>
    where T: RealNumber {
    /// Creates a root raised cosine function.
    pub fn new(rolloff: T) -> Self {
        RaiseCosineFuncton { rolloff: rolloff }
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::RealNumber;
    use std::fmt::Debug;

    fn conv_test<T, C>(conv: C, expected: &[T], step: T, tolerance: T)
        where T: RealNumber + Debug,
              C: RealTimeConvFunction<T> {
        let mut result = vec![T::zero(); expected.len()];
        let mut j = -(expected.len() as isize / 2);
        for i in 0..result.len() {
            result[i] = conv.calc(T::from(j).unwrap() * step);
            j += 1;
        }

        for i in 0..result.len() {
            if (result[i] - expected[i]).abs() > tolerance {
                panic!("assertion failed: {:?} != {:?}", result, expected);
            }
        }
    }

	#[test]
	fn raised_cosine32_test()
	{
        let window = RaiseCosineFuncton::new(0.35);
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        conv_test(window, &expected, 0.2, 1e-4);
	}

    #[test]
    fn lookup_table32_test() {
        let window = RaiseCosineFuncton::new(0.35);
        let table = RealTimeLinearTableLookup::<f64>::from_conv_function(&window, 0.2, 0.0, 10);
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        conv_test(table, &expected, 0.2, 1e-4);
    }

    #[test]
    fn linear_interpolation_lookup_table32_test() {
        let window = RaiseCosineFuncton::new(0.35);
        let table = RealTimeLinearTableLookup::<f64>::from_conv_function(&window, 0.4, 0.0, 10);
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        conv_test(table, &expected, 0.2, 0.1);
    }
}<commit_msg>Fixed documentation error<commit_after>//! Types around a convolution, see also https://en.wikipedia.org/wiki/Convolution.
//!
//! Convolutions in this library can be defined in time or frequency domain. In
//! frequency domain the convolution is automatically transformed into a multiplication
//! which is the analog operation to a convolution in time domain.
use RealNumber;
use num::traits::Zero;
use num::complex::{Complex, Complex32,Complex64};
use vector_types::{
    RealTimeVector,
    ComplexTimeVector,
    ComplexFreqVector
};
use vector_types::definitions::{
    DataVector,
    RealVectorOperations,
    ComplexVectorOperations
};

use vector_types::time_freq_impl::{
    TimeDomainOperations,
    FrequencyDomainOperations
};

/// A convolution function in time domain and real number space
pub trait RealTimeConvFunction<T>
    where T: RealNumber {
    /// Calculates the convolution for a real data point
    fn calc(&self, x: T) -> T;
}

/// A convolution function in time domain and complex number space
pub trait ComplexTimeConvFunction<T>
    where T: RealNumber {
    /// Calculates the convolution for a real data point
    fn calc(&self, x: T) -> Complex<T>;
}

/// A convolution function in frequency domain and complex number space
pub trait ComplexFrequencyConvFunction<T>
    where T: RealNumber {
    /// Calculates the convolution for a real data point
    fn calc(&self, x: T) -> Complex<T>;
}

/// Allows to create a lookup table with linear interpolation between table points.
/// This usually speeds up a convolution and sacrifies accuracy.
pub struct RealTimeLinearTableLookup<T>
    where T: RealNumber {
    table: Vec<T>,
    delta: T,
    offset: T
}

/// Allows to create a lookup table with linear interpolation between table points.
/// This usually speeds up a convolution and sacrifies accuracy.
pub struct ComplexTimeLinearTableLookup<T>
    where T: RealNumber {
    table: Vec<Complex<T>>,
    delta: T,
    offset: T
}

/// Allows to create a lookup table with linear interpolation between table points.
/// This usually speeds up a convolution and sacrifies accuracy.
pub struct ComplexFrequencyLinearTableLookup<T>
    where T: RealNumber {
    table: Vec<Complex<T>>,
    delta: T,
    offset: T
}

macro_rules! add_linear_table_lookup_impl {
    ($($name: ident: $conv_type: ident, $($data_type: ident, $result_type:ident),*);*) => {
        $(
            $(
                impl $conv_type<$data_type> for $name<$data_type> {
                    fn calc(&self, x: $data_type) -> $result_type {
                        let len = self.table.len();
                        let center = len / 2;
                        let center_float = center as $data_type;
                        let x = x / self.delta - self.offset + center_float;
                        let round_float = x.round();
                        let round = round_float as usize;
                        if round >= len {
                            return $result_type::zero();
                        }

                        let round_tolerance = 1e-6;
                        if (x - round_float).abs() < round_tolerance {
                            return self.table[round];
                        }

                        if x > round_float {
                            let other = round + 1;
                            if other >= len {
                                return self.table[round];
                            }
                            let y0 = self.table[round];
                            let x0 = round_float;
                            let y1 = self.table[other];
                            return y0 + (y1 - y0) * (x - x0);
                        } else {
                            if round == 0 {
                                return self.table[round];
                            }
                            let other = round - 1;
                            let y0 = self.table[round];
                            let x0 = round_float;
                            let y1 = self.table[other];
                            return y0 + (y1 - y0) * (x0 - x);
                        }
                    }
                }

                impl $name<$data_type> {
                    /// Creates a lookup table by putting the pieces together.
                    pub fn from_raw_parts(table: &[$result_type], delta: $data_type, offset: $data_type) -> Self {
                        let owned_table = Vec::from(table);
                        $name { table: owned_table, delta: delta, offset: offset }
                    }

                    /// Creates a lookup table from another convolution function. The `delta` argument
                    /// can be used to balance performance vs. accuracy.
                    pub fn from_conv_function(other: &$conv_type<$data_type>, delta: $data_type, offset: $data_type, len: usize) -> Self {
                        let center = (len / 2) as isize;
                        let mut table = vec![$result_type::zero(); len];
                        let mut i = -center;
                        for n in &mut table {
                            *n = other.calc((i as $data_type) * delta);
                            i += 1;
                        }
                        $name { table: table, delta: delta, offset: offset }
                    }
                }
            )*
        )*
    }
}
add_linear_table_lookup_impl!(
    RealTimeLinearTableLookup: RealTimeConvFunction, f32, f32, f64, f64;
    ComplexTimeLinearTableLookup: ComplexTimeConvFunction, f32, Complex32, f64, Complex64;
    ComplexFrequencyLinearTableLookup: ComplexFrequencyConvFunction, f32, Complex32, f64, Complex64);

macro_rules! add_real_time_linear_table_impl {
    ($($data_type: ident),*) => {
        $(
            impl RealTimeLinearTableLookup<$data_type> {
                /// Convert the lookup table into complex number space
                pub fn to_complex(&self) -> ComplexTimeLinearTableLookup<$data_type> {
                    let vector = RealTimeVector::from_array(&self.table);
                    let complex = vector.to_complex().expect("to_complex shouldn't fail");
                    let complex = complex.complex_data();
                    let mut table = Vec::with_capacity(complex.len());
                    for n in complex {
                        table.push(*n);
                    }
                    ComplexTimeLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }
            }
        )*
    }
}
add_real_time_linear_table_impl!(f32, f64);

macro_rules! add_complex_time_linear_table_impl {
    ($($data_type: ident),*) => {
        $(
            impl ComplexTimeLinearTableLookup<$data_type> {
                /// Convert the lookup table into real number space
                pub fn to_real(self) -> RealTimeLinearTableLookup<$data_type> {
                    let vector = ComplexTimeVector::from_complex(&self.table);
                    let real = vector.to_real().expect("to_complex shouldn't fail");
                    let real = real.data();
                    let mut table = Vec::with_capacity(real.len());
                    for n in real {
                        table.push(*n);
                    }
                    RealTimeLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }

                /// Convert the lookup table into frequency domain
                pub fn fft(self) -> ComplexFrequencyLinearTableLookup<$data_type> {
                    let vector = ComplexTimeVector::from_complex(&self.table);
                    let freq = vector.fft().expect("vector fft shouldn't fail");
                    let freq = freq.complex_data();
                    let mut table = Vec::with_capacity(freq.len());
                    for n in freq {
                        table.push(*n);
                    }
                    ComplexFrequencyLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }
            }
        )*
    }
}
add_complex_time_linear_table_impl!(f32, f64);

macro_rules! add_complex_frequency_linear_table_impl {
    ($($data_type: ident),*) => {
        $(
            impl ComplexFrequencyLinearTableLookup<$data_type> {

                /// Convert the lookup table into time domain
                pub fn ifft(self) -> ComplexTimeLinearTableLookup<$data_type> {
                    let vector = ComplexFreqVector::from_complex(&self.table);
                    let time = vector.ifft().expect("vector ifft shouldn't fail");
                    let time = time.complex_data();
                    let mut table = Vec::with_capacity(time.len());
                    for n in time {
                        table.push(*n);
                    }
                    ComplexTimeLinearTableLookup { table: table, delta: self.delta, offset: self.offset }
                }
            }
        )*
    }
}
add_complex_frequency_linear_table_impl!(f32, f64);

/// Raised cosine function according to https://en.wikipedia.org/wiki/Raised-cosine_filter
pub struct  RaiseCosineFuncton<T>
    where T: RealNumber {
    rolloff: T
}

impl<T> RealTimeConvFunction<T> for RaiseCosineFuncton<T>
    where T: RealNumber {
    fn calc(&self, x: T) -> T {
        if x == T::zero() {
            return T::one();
        }

        let one = T::one();
        let two = T::from(2.0).unwrap();
        let pi = two * one.asin();
        let four = two * two;
        if x.abs() == one / (two * self.rolloff) {
            let arg = pi / two / self.rolloff;
            return (arg).sin() / arg * pi / four;
        }

        let pi_x = pi * x;
        let arg = two * self.rolloff * x;
        return pi_x.sin() * (pi_x * self.rolloff).cos() / pi_x / (one - (arg * arg))
    }
}

impl<T> RaiseCosineFuncton<T>
    where T: RealNumber {
    /// Creates a raised cosine function.
    pub fn new(rolloff: T) -> Self {
        RaiseCosineFuncton { rolloff: rolloff }
    }
}

#[cfg(test)]
mod tests {
	use super::*;
    use super::super::RealNumber;
    use std::fmt::Debug;

    fn conv_test<T, C>(conv: C, expected: &[T], step: T, tolerance: T)
        where T: RealNumber + Debug,
              C: RealTimeConvFunction<T> {
        let mut result = vec![T::zero(); expected.len()];
        let mut j = -(expected.len() as isize / 2);
        for i in 0..result.len() {
            result[i] = conv.calc(T::from(j).unwrap() * step);
            j += 1;
        }

        for i in 0..result.len() {
            if (result[i] - expected[i]).abs() > tolerance {
                panic!("assertion failed: {:?} != {:?}", result, expected);
            }
        }
    }

	#[test]
	fn raised_cosine32_test()
	{
        let window = RaiseCosineFuncton::new(0.35);
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        conv_test(window, &expected, 0.2, 1e-4);
	}

    #[test]
    fn lookup_table32_test() {
        let window = RaiseCosineFuncton::new(0.35);
        let table = RealTimeLinearTableLookup::<f64>::from_conv_function(&window, 0.2, 0.0, 10);
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        conv_test(table, &expected, 0.2, 1e-4);
    }

    #[test]
    fn linear_interpolation_lookup_table32_test() {
        let window = RaiseCosineFuncton::new(0.35);
        let table = RealTimeLinearTableLookup::<f64>::from_conv_function(&window, 0.4, 0.0, 10);
        let expected =
            [0.0, 0.2171850639713355, 0.4840621929215732, 0.7430526238101408, 0.9312114164253432,
             1.0, 0.9312114164253432, 0.7430526238101408, 0.4840621929215732, 0.2171850639713355];
        conv_test(table, &expected, 0.2, 0.1);
    }
}<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#![allow(dead_code, non_camel_case_types)]

use pa::error::Error;
use libc::{c_char, c_double, c_ulong, c_void};
use std::ffi::{CStr, CString};

use pa::{
    DeviceIndex,
    HostApiIndex,
    StreamCallbackTimeInfo,
    StreamInfo,
    Time,
    StreamCallbackResult
};

// Sample format
pub type SampleFormat = u64;
pub const PA_FLOAT_32        : SampleFormat = 0x00000001;
pub const PA_INT_32          : SampleFormat = 0x00000002;
// pub const PA_INT_24       : SampleFormat = 0x00000004;
pub const PA_INT_16          : SampleFormat = 0x00000008;
pub const PA_INT_8           : SampleFormat = 0x00000010;
pub const PA_UINT_8          : SampleFormat = 0x00000020;
pub const PA_CUSTOM_FORMAT   : SampleFormat = 0x00010000;
pub const PA_NON_INTERLEAVED : SampleFormat = 0x80000000;

// Stream flags
pub type StreamFlags = u64;
pub const PA_NO_FLAG                                    : StreamFlags = 0;
pub const PA_CLIP_OFF                                   : StreamFlags = 0x00000001;
pub const PA_DITHER_OFF                                 : StreamFlags = 0x00000002;
pub const PA_NEVER_DROP_INPUT                           : StreamFlags = 0x00000004;
pub const PA_PRIME_OUTPUT_BUFFERS_USING_STREAM_CALLBACK : StreamFlags = 0x00000008;
pub const PA_PLATFORM_SPECIFIC_FLAGS                    : StreamFlags = 0xFFFF0000;

// Stream callback falgs.
pub type StreamCallbackFlags = u64;
pub const INPUT_UNDERFLOW  : StreamCallbackFlags = 0x00000001;
pub const INPUT_OVERFLOW   : StreamCallbackFlags = 0x00000002;
pub const OUTPUT_UNDERFLOW : StreamCallbackFlags = 0x00000004;
pub const OUTPUT_OVERFLOW  : StreamCallbackFlags = 0x00000008;
pub const PRIMING_OUTPUT   : StreamCallbackFlags = 0x00000010;

/// Unchanging unique identifiers for each supported host API
pub type HostApiTypeId = i32;
pub const PA_IN_DEVELOPMENT: HostApiTypeId = 0;
pub const PA_DIRECT_SOUND: HostApiTypeId = 1;
pub const PA_MME: HostApiTypeId = 2;
pub const PA_ASIO: HostApiTypeId = 3;
pub const PA_SOUND_MANAGER: HostApiTypeId = 4;
pub const PA_CORE_AUDIO: HostApiTypeId = 5;
pub const PA_OSS: HostApiTypeId = 7;
pub const PA_ALSA: HostApiTypeId = 8;
pub const PA_AL: HostApiTypeId = 9;
pub const PA_BE_OS: HostApiTypeId = 10;
pub const PA_WDMKS: HostApiTypeId = 11;
pub const PA_JACK: HostApiTypeId = 12;
pub const PA_WASAPI: HostApiTypeId = 13;
pub const PA_AUDIO_SCIENCE_HPI: HostApiTypeId = 14;

pub type C_PaStream = c_void;

#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
pub struct C_PaStreamParameters {
    pub device : DeviceIndex,
    pub channel_count : i32,
    pub sample_format : SampleFormat,
    pub suggested_latency : Time,
    pub host_api_specific_stream_info : *mut c_void
}

#[repr(C)]
pub struct C_PaDeviceInfo {
    pub struct_version: i32,
    pub name: *const c_char,
    pub host_api: HostApiIndex,
    pub max_input_channels: i32,
    pub max_output_channels: i32,
    pub default_low_input_latency: Time,
    pub default_low_output_latency: Time,
    pub default_high_input_latency: Time,
    pub default_high_output_latency: Time,
    pub default_sample_rate: c_double
}

#[repr(C)]
pub struct C_PaHostErrorInfo {
    pub error_code: u32,
    pub error_text: *const c_char
}

#[repr(C)]
pub struct C_PaHostApiInfo {
    pub struct_version: i32,
    pub host_type: i32,
    pub name: *const c_char,
    pub device_count: i32,
    pub default_input_device: i32,
    pub default_output_device: i32
}

pub type C_PaStreamCallbackFn =
    extern "C" fn(*const c_void,
                  *mut c_void,
                  c_ulong,
                  *const StreamCallbackTimeInfo,
                  StreamCallbackFlags,
                  *mut c_void) -> StreamCallbackResult;

extern "C" {

    /// PortAudio portable API

    pub fn Pa_GetVersion() -> i32;
    pub fn Pa_GetVersionText() -> *const c_char;
    pub fn Pa_GetErrorText(errorCode : Error) -> *const c_char;
    pub fn Pa_Initialize() -> Error;
    pub fn Pa_Terminate() -> Error;
    pub fn Pa_GetHostApiCount() -> HostApiIndex;
    pub fn Pa_GetDefaultHostApi() -> HostApiIndex;
    pub fn Pa_GetHostApiInfo(hostApi : HostApiIndex) -> *const C_PaHostApiInfo;
    pub fn Pa_HostApiTypeIdToHostApiIndex(type_id : HostApiTypeId) -> HostApiIndex;
    pub fn Pa_HostApiDeviceIndexToDeviceIndex(hostApi : HostApiIndex, hostApiDeviceIndex : i32) -> DeviceIndex;
    pub fn Pa_GetLastHostErrorInfo() -> *const C_PaHostErrorInfo;
    pub fn Pa_GetDeviceCount() -> DeviceIndex;
    pub fn Pa_GetDefaultInputDevice() -> DeviceIndex;
    pub fn Pa_GetDefaultOutputDevice() -> DeviceIndex;
    pub fn Pa_GetDeviceInfo(device : DeviceIndex) -> *const C_PaDeviceInfo;
    pub fn Pa_IsFormatSupported(input_parameters : *const C_PaStreamParameters, outputParameters : *const C_PaStreamParameters, sampleRate : c_double) -> Error;
    pub fn Pa_GetSampleSize(format : SampleFormat) -> i32;
    pub fn Pa_Sleep(msec : i32) -> ();
    pub fn Pa_OpenStream(stream : *mut *mut C_PaStream,
                         inputParameters : *const C_PaStreamParameters,
                         outputParameters : *const C_PaStreamParameters,
                         sampleRate : c_double,
                         framesPerBuffer : u32,
                         streamFlags : StreamFlags,
                         streamCallback : Option<C_PaStreamCallbackFn>,
                         userData : *mut c_void)
                         -> Error;
    pub fn Pa_OpenDefaultStream(stream : *mut *mut C_PaStream,
                                numInputChannels : i32,
                                numOutputChannels : i32,
                                sampleFormat : SampleFormat,
                                sampleRate : c_double,
                                framesPerBuffer : u32,
                                streamCallback : Option<C_PaStreamCallbackFn>,
                                userData : *mut c_void)
                                -> Error;
    pub fn Pa_CloseStream(stream : *mut C_PaStream) -> Error;
    //pub fn Pa_SetStreamFinishedCallback (stream : *PaStream, PaStreamFinishedCallback *streamFinishedCallback) -> Error;
    pub fn Pa_StartStream(stream : *mut C_PaStream) -> Error;
    pub fn Pa_StopStream(stream : *mut C_PaStream) -> Error;
    pub fn Pa_AbortStream(stream : *mut C_PaStream) -> Error;
    pub fn Pa_IsStreamStopped(stream : *mut C_PaStream) -> Error;
    pub fn Pa_IsStreamActive(stream : *mut C_PaStream) -> i32;
    pub fn Pa_GetStreamInfo(stream : *mut C_PaStream) -> *const StreamInfo;
    pub fn Pa_GetStreamTime(stream : *mut C_PaStream) -> Time;
    pub fn Pa_GetStreamCpuLoad(stream : *mut C_PaStream) -> c_double;
    pub fn Pa_ReadStream(stream : *mut C_PaStream, buffer : *mut c_void, frames : u32) -> Error;
    pub fn Pa_WriteStream(stream : *mut C_PaStream, buffer : *mut c_void, frames : u32) -> Error;
    pub fn Pa_GetStreamReadAvailable(stream : *mut C_PaStream) -> i64;
    pub fn Pa_GetStreamWriteAvailable(stream : *mut C_PaStream) -> i64;

    // PortAudio Specific ASIO
    pub fn PaAsio_GetAvailableBufferSizes(device : DeviceIndex, minBufferSizeFrames : *mut i32, maxBufferSizeFrames : *mut i32, preferredBufferSizeFrames : *mut i32, granularity : *mut i32) -> Error;
    pub fn PaAsio_GetInputChannelName(device : DeviceIndex, channelIndex : i32, channelName : *mut *const c_char) -> Error;
    pub fn PaAsio_GetOutputChannelName(device : DeviceIndex, channelIndex : i32, channelName : *mut *const c_char) -> Error;
    pub fn PaAsio_SetStreamSampleRate(stream : *mut C_PaStream, sampleRate : c_double) -> Error;

    // PortAudio Specific MAC_CORE
    pub fn PaMacCore_GetStreamInputDevice(s : *mut C_PaStream) -> DeviceIndex;
    pub fn PaMacCore_GetStreamOutputDevice(s : *mut C_PaStream) -> DeviceIndex;
    // pub fn PaMacCore_GetChannelName (int device, int channelIndex, bool intput) -> *c_char
    pub fn PaMacCore_GetBufferSizeRange(device : DeviceIndex, minBufferSizeFrames : *mut u32, maxBufferSizeFrames : *mut u32) -> Error;
    //pub fn PaMacCore_SetupStreamInfo(PaMacCoreStreamInfo *data, unsigned long flags) -> ();
    //pub fn PaMacCore_SetupChannelMap(PaMacCoreStreamInfo *data, const SInt32 *const channelMap, unsigned long channelMapSize) -> ();
}

/// A function to convert C strings to Rust strings
pub fn c_str_to_string<'a>(c_str: &'a *const c_char) -> String {
    unsafe {
        String::from_utf8_lossy(CStr::from_ptr(*c_str).to_bytes()).into_owned()
    }
}

/// A function to convert Rust strings to C strings
pub fn string_to_c_str(rust_str: &String) -> *const c_char {
    match CString::new(rust_str.as_bytes()) {
        Ok(c_string) => c_string.as_ptr(),
        Err(err) => panic!(err),
    }
}
<commit_msg>Add C_PaStreamCallbackTimeInfo, DeviceIndex and HostApiIndex to ffi to keep them separate from rusty types. Change Error return types on ffi functions to i32 so that they can be properly translated to Errors rather than autocasting<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#![allow(dead_code, non_camel_case_types)]

use pa::error::Error;
use libc::{c_char, c_double, c_ulong, c_void};
use std::ffi::{CStr, CString};

use pa::{
    StreamInfo,
    Time,
    StreamCallbackResult
};

pub type DeviceIndex = i32;
pub type HostApiIndex = i32;

// Sample format
pub type SampleFormat = u64;
pub const PA_FLOAT_32        : SampleFormat = 0x00000001;
pub const PA_INT_32          : SampleFormat = 0x00000002;
pub const PA_INT_24          : SampleFormat = 0x00000004;
pub const PA_INT_16          : SampleFormat = 0x00000008;
pub const PA_INT_8           : SampleFormat = 0x00000010;
pub const PA_UINT_8          : SampleFormat = 0x00000020;
pub const PA_CUSTOM_FORMAT   : SampleFormat = 0x00010000;
pub const PA_NON_INTERLEAVED : SampleFormat = 0x80000000;

// Stream flags
pub type StreamFlags = u64;
pub const PA_NO_FLAG                                    : StreamFlags = 0;
pub const PA_CLIP_OFF                                   : StreamFlags = 0x00000001;
pub const PA_DITHER_OFF                                 : StreamFlags = 0x00000002;
pub const PA_NEVER_DROP_INPUT                           : StreamFlags = 0x00000004;
pub const PA_PRIME_OUTPUT_BUFFERS_USING_STREAM_CALLBACK : StreamFlags = 0x00000008;
pub const PA_PLATFORM_SPECIFIC_FLAGS                    : StreamFlags = 0xFFFF0000;

// Stream callback falgs.
pub type StreamCallbackFlags = u64;
pub const INPUT_UNDERFLOW  : StreamCallbackFlags = 0x00000001;
pub const INPUT_OVERFLOW   : StreamCallbackFlags = 0x00000002;
pub const OUTPUT_UNDERFLOW : StreamCallbackFlags = 0x00000004;
pub const OUTPUT_OVERFLOW  : StreamCallbackFlags = 0x00000008;
pub const PRIMING_OUTPUT   : StreamCallbackFlags = 0x00000010;

/// Unchanging unique identifiers for each supported host API
pub type HostApiTypeId = i32;
pub const PA_IN_DEVELOPMENT: HostApiTypeId = 0;
pub const PA_DIRECT_SOUND: HostApiTypeId = 1;
pub const PA_MME: HostApiTypeId = 2;
pub const PA_ASIO: HostApiTypeId = 3;
pub const PA_SOUND_MANAGER: HostApiTypeId = 4;
pub const PA_CORE_AUDIO: HostApiTypeId = 5;
pub const PA_OSS: HostApiTypeId = 7;
pub const PA_ALSA: HostApiTypeId = 8;
pub const PA_AL: HostApiTypeId = 9;
pub const PA_BE_OS: HostApiTypeId = 10;
pub const PA_WDMKS: HostApiTypeId = 11;
pub const PA_JACK: HostApiTypeId = 12;
pub const PA_WASAPI: HostApiTypeId = 13;
pub const PA_AUDIO_SCIENCE_HPI: HostApiTypeId = 14;

#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct C_PaStreamCallbackTimeInfo {
    pub input_buffer_adc_time: Time,
    pub current_time: Time,
    pub output_buffer_dac_time: Time
}

pub type C_PaStream = c_void;

#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
pub struct C_PaStreamParameters {
    pub device : DeviceIndex,
    pub channel_count : i32,
    pub sample_format : SampleFormat,
    pub suggested_latency : Time,
    pub host_api_specific_stream_info : *mut c_void
}

#[repr(C)]
pub struct C_PaDeviceInfo {
    pub struct_version: i32,
    pub name: *const c_char,
    pub host_api: HostApiIndex,
    pub max_input_channels: i32,
    pub max_output_channels: i32,
    pub default_low_input_latency: Time,
    pub default_low_output_latency: Time,
    pub default_high_input_latency: Time,
    pub default_high_output_latency: Time,
    pub default_sample_rate: c_double
}

#[repr(C)]
pub struct C_PaHostErrorInfo {
    pub error_code: u32,
    pub error_text: *const c_char
}

#[repr(C)]
pub struct C_PaHostApiInfo {
    pub struct_version: i32,
    pub host_type: i32,
    pub name: *const c_char,
    pub device_count: i32,
    pub default_input_device: i32,
    pub default_output_device: i32
}

pub type C_PaStreamCallbackFn =
    extern "C" fn(*const c_void,
                  *mut c_void,
                  c_ulong,
                  *const C_PaStreamCallbackTimeInfo,
                  StreamCallbackFlags,
                  *mut c_void) -> StreamCallbackResult;

extern "C" {

    /// PortAudio portable API

    pub fn Pa_GetVersion() -> i32;
    pub fn Pa_GetVersionText() -> *const c_char;
    pub fn Pa_GetErrorText(errorCode : Error) -> *const c_char;
    pub fn Pa_Initialize() -> Error;
    pub fn Pa_Terminate() -> Error;
    pub fn Pa_GetHostApiCount() -> HostApiIndex;
    pub fn Pa_GetDefaultHostApi() -> HostApiIndex;
    pub fn Pa_GetHostApiInfo(hostApi : HostApiIndex) -> *const C_PaHostApiInfo;
    pub fn Pa_HostApiTypeIdToHostApiIndex(type_id : HostApiTypeId) -> HostApiIndex;
    pub fn Pa_HostApiDeviceIndexToDeviceIndex(hostApi : HostApiIndex, hostApiDeviceIndex : i32) -> DeviceIndex;
    pub fn Pa_GetLastHostErrorInfo() -> *const C_PaHostErrorInfo;
    pub fn Pa_GetDeviceCount() -> DeviceIndex;
    pub fn Pa_GetDefaultInputDevice() -> DeviceIndex;
    pub fn Pa_GetDefaultOutputDevice() -> DeviceIndex;
    pub fn Pa_GetDeviceInfo(device : DeviceIndex) -> *const C_PaDeviceInfo;
    pub fn Pa_IsFormatSupported(input_parameters : *const C_PaStreamParameters, outputParameters : *const C_PaStreamParameters, sampleRate : c_double) -> Error;
    pub fn Pa_GetSampleSize(format : SampleFormat) -> i32;
    pub fn Pa_Sleep(msec : i32) -> ();
    pub fn Pa_OpenStream(stream : *mut *mut C_PaStream,
                         inputParameters : *const C_PaStreamParameters,
                         outputParameters : *const C_PaStreamParameters,
                         sampleRate : c_double,
                         framesPerBuffer : u32,
                         streamFlags : StreamFlags,
                         streamCallback : Option<C_PaStreamCallbackFn>,
                         userData : *mut c_void)
                         -> Error;
    pub fn Pa_OpenDefaultStream(stream : *mut *mut C_PaStream,
                                numInputChannels : i32,
                                numOutputChannels : i32,
                                sampleFormat : SampleFormat,
                                sampleRate : c_double,
                                framesPerBuffer : u32,
                                streamCallback : Option<C_PaStreamCallbackFn>,
                                userData : *mut c_void)
                                -> Error;
    pub fn Pa_CloseStream(stream : *mut C_PaStream) -> Error;
    //pub fn Pa_SetStreamFinishedCallback (stream : *PaStream, PaStreamFinishedCallback *streamFinishedCallback) -> Error;
    pub fn Pa_StartStream(stream : *mut C_PaStream) -> i32;
    pub fn Pa_StopStream(stream : *mut C_PaStream) -> i32;
    pub fn Pa_AbortStream(stream : *mut C_PaStream) -> i32;
    pub fn Pa_IsStreamStopped(stream : *mut C_PaStream) -> i32;
    pub fn Pa_IsStreamActive(stream : *mut C_PaStream) -> i32;
    pub fn Pa_GetStreamInfo(stream : *mut C_PaStream) -> *const StreamInfo;
    pub fn Pa_GetStreamTime(stream : *mut C_PaStream) -> Time;
    pub fn Pa_GetStreamCpuLoad(stream : *mut C_PaStream) -> c_double;
    pub fn Pa_ReadStream(stream : *mut C_PaStream, buffer : *mut c_void, frames : u32) -> i32;
    pub fn Pa_WriteStream(stream : *mut C_PaStream, buffer : *mut c_void, frames : u32) -> i32;
    pub fn Pa_GetStreamReadAvailable(stream : *mut C_PaStream) -> i64;
    pub fn Pa_GetStreamWriteAvailable(stream : *mut C_PaStream) -> i64;

    // PortAudio Specific ASIO
    pub fn PaAsio_GetAvailableBufferSizes(device : DeviceIndex, minBufferSizeFrames : *mut i32, maxBufferSizeFrames : *mut i32, preferredBufferSizeFrames : *mut i32, granularity : *mut i32) -> Error;
    pub fn PaAsio_GetInputChannelName(device : DeviceIndex, channelIndex : i32, channelName : *mut *const c_char) -> Error;
    pub fn PaAsio_GetOutputChannelName(device : DeviceIndex, channelIndex : i32, channelName : *mut *const c_char) -> Error;
    pub fn PaAsio_SetStreamSampleRate(stream : *mut C_PaStream, sampleRate : c_double) -> Error;

    // PortAudio Specific MAC_CORE
    pub fn PaMacCore_GetStreamInputDevice(s : *mut C_PaStream) -> DeviceIndex;
    pub fn PaMacCore_GetStreamOutputDevice(s : *mut C_PaStream) -> DeviceIndex;
    // pub fn PaMacCore_GetChannelName (int device, int channelIndex, bool intput) -> *c_char
    pub fn PaMacCore_GetBufferSizeRange(device : DeviceIndex, minBufferSizeFrames : *mut u32, maxBufferSizeFrames : *mut u32) -> Error;
    //pub fn PaMacCore_SetupStreamInfo(PaMacCoreStreamInfo *data, unsigned long flags) -> ();
    //pub fn PaMacCore_SetupChannelMap(PaMacCoreStreamInfo *data, const SInt32 *const channelMap, unsigned long channelMapSize) -> ();
}

/// A function to convert C strings to Rust strings
pub fn c_str_to_string<'a>(c_str: &'a *const c_char) -> String {
    unsafe {
        String::from_utf8_lossy(CStr::from_ptr(*c_str).to_bytes()).into_owned()
    }
}

/// A function to convert Rust strings to C strings
pub fn string_to_c_str(rust_str: &String) -> *const c_char {
    match CString::new(rust_str.as_bytes()) {
        Ok(c_string) => c_string.as_ptr(),
        Err(err) => panic!(err),
    }
}
<|endoftext|>