<commit_before>use config::Config;
use error::{Error, Result};
use post::Post;
use std::env;
use std::fs::{self, DirBuilder};
use std::io::Write;
use std::path::PathBuf;
use tera::{Context, Tera};

fn write_file(filename: PathBuf, config: &Config, content: &[u8]) -> Result<()> {
    let mut out = ::get_opener(config.force.unwrap_or(false))
        .open(&filename)
        .map_err(|e| format!("fail to create {:?}: {}", &filename, e))?;

    out.write(content)?;
    Ok(())
}

fn generate_post(tera: &Tera, base: &Context, config: &Config, post: &Post) -> Result<()> {
    let out_dir = config.out_dir
                        .as_ref()
                        .map(|s| PathBuf::from(s))
                        .unwrap_or(env::current_dir()?);
    let mut ctx = Context::new();
    ctx.extend(base.clone());
    ctx.add("post", post);

    let rendered = tera.render(::POST_FILE, &ctx)
        .map_err(|e| Error::new(format!("fail to generate {:?}: {}", post.path, e)))?;

    let mut filename = if post.meta.is_article {
        let dir = post.meta.ts.format("%Y/%m/%d").to_string();
        DirBuilder::new()
            .recursive(true)
            .create(&dir)
            .map_err(|e| format!("fail to create {}: {}", &dir, e))?;

        out_dir.join(&dir).join(&post.meta.link)
    }
    else {
        out_dir.join(&post.meta.link)
    };

    if !filename.set_extension("html") {
        return Err(Error::new(format!("bad output filename {:?}", filename)));
    }

    write_file(filename, config, rendered.as_bytes())
}

fn generate_site_page(tera: &Tera, ctx: &Context, config: &Config) -> Result<()> {
    let out_dir = config.out_dir
                        .as_ref()
                        .map(|s| PathBuf::from(s))
                        .unwrap_or(env::current_dir()?);

    for file in &[::INDEX_FILE, ::ARCHIVE_FILE] {
        let out_path = out_dir.as_path().join(&file);
        println!("generating {:?}", out_path);
        tera.render(file, &ctx)
            .map_err(|e| Error::new(format!("fail to generate {:?}: {}", out_path, e)))
            .and_then(|rendered| write_file(out_path, &config, rendered.as_bytes()))?;
    }

    Ok(())
}

pub fn generate(config: Config) -> Result<()> {
    let in_dir = config.in_dir
                       .as_ref()
                       .map(|s| PathBuf::from(s))
                       .unwrap_or(env::current_dir()?);

    let mut tera = Tera::new(in_dir.join(::THEME_DIR)
                                   .join("*")
                                   .to_str()
                                   .ok_or(Error::new("cannot get templates".to_string()))?)
        .map_err(|e| format!("compile templates fails: {}", e))?;
    // turn off auto escaping
    tera.autoescape_on(vec![]);

    let mut articles = vec![];
    let mut pages = vec![];
    for entry in fs::read_dir(in_dir.join(::SRC_DIR))? {
        let post = Post::from_file(&entry?.path())?;
        if post.meta.is_article {
            articles.push(post);
        }
        else {
            pages.push(post);
        }
    }
    articles.sort_by(|x, y| y.meta.ts.cmp(&x.meta.ts));
    pages.sort_by(|x, y| y.meta.ts.cmp(&x.meta.ts));

    let mut ctx = Context::new();
    ctx.add("articles", &articles);
    ctx.add("pages", &pages);
    ctx.add("config", &config);
    if let Some(p) = articles.first() {
        ctx.add("latest_article", p);
    }

    for post in articles.iter().chain(pages.iter()) {
        println!("generating {:?}", post.path);
        generate_post(&tera, &ctx, &config, &post)?;
    }

    generate_site_page(&tera, &ctx, &config)?;

    Ok(())
}
<commit_msg>Fix output directory of posts<commit_after>use config::Config;
use error::{Error, Result};
use post::Post;
use std::env;
use std::fs::{self, DirBuilder};
use std::io::Write;
use std::path::PathBuf;
use tera::{Context, Tera};

fn write_file(filename: PathBuf, config: &Config, content: &[u8]) -> Result<()> {
    let mut out = ::get_opener(config.force.unwrap_or(false))
        .open(&filename)
        .map_err(|e| format!("fail to create {:?}: {}", &filename, e))?;

    out.write(content)?;
    Ok(())
}

fn generate_post(tera: &Tera, base: &Context, config: &Config, post: &Post) -> Result<()> {
    let out_dir = config.out_dir
                        .as_ref()
                        .map(|s| PathBuf::from(s))
                        .unwrap_or(env::current_dir()?);
    let mut ctx = Context::new();
    ctx.extend(base.clone());
    ctx.add("post", post);

    let rendered = tera.render(::POST_FILE, &ctx)
        .map_err(|e| Error::new(format!("fail to generate {:?}: {}", post.path, e)))?;

    let mut filename = if post.meta.is_article {
        let path = post.meta.ts.format("%Y/%m/%d").to_string();
        let path = out_dir.join(path);
        DirBuilder::new()
            .recursive(true)
            .create(&path)
            .map_err(|e| format!("fail to create {:?}: {}", &path, e))?;
        path.join(&post.meta.link)
    }
    else {
        out_dir.join(&post.meta.link)
    };

    if !filename.set_extension("html") {
        return Err(Error::new(format!("bad output filename {:?}", filename)));
    }

    write_file(filename, config, rendered.as_bytes())
}

fn generate_site_page(tera: &Tera, ctx: &Context, config: &Config) -> Result<()> {
    let out_dir = config.out_dir
                        .as_ref()
                        .map(|s| PathBuf::from(s))
                        .unwrap_or(env::current_dir()?);

    for file in &[::INDEX_FILE, ::ARCHIVE_FILE] {
        let out_path = out_dir.as_path().join(&file);
        println!("generating {:?}", out_path);
        tera.render(file, &ctx)
            .map_err(|e| Error::new(format!("fail to generate {:?}: {}", out_path, e)))
            .and_then(|rendered| write_file(out_path, &config, rendered.as_bytes()))?;
    }

    Ok(())
}

pub fn generate(config: Config) -> Result<()> {
    let in_dir = config.in_dir
                       .as_ref()
                       .map(|s| PathBuf::from(s))
                       .unwrap_or(env::current_dir()?);

    let mut tera = Tera::new(in_dir.join(::THEME_DIR)
                                   .join("*")
                                   .to_str()
                                   .ok_or(Error::new("cannot get templates".to_string()))?)
        .map_err(|e| format!("compile templates fails: {}", e))?;
    // turn off auto escaping
    tera.autoescape_on(vec![]);

    let mut articles = vec![];
    let mut pages = vec![];
    for entry in fs::read_dir(in_dir.join(::SRC_DIR))? {
        let post = Post::from_file(&entry?.path())?;
        if post.meta.is_article {
            articles.push(post);
        }
        else {
            pages.push(post);
        }
    }
    articles.sort_by(|x, y| y.meta.ts.cmp(&x.meta.ts));
    pages.sort_by(|x, y| y.meta.ts.cmp(&x.meta.ts));

    let mut ctx = Context::new();
    ctx.add("articles", &articles);
    ctx.add("pages", &pages);
    ctx.add("config", &config);
    if let Some(p) = articles.first() {
        ctx.add("latest_article", p);
    }

    for post in articles.iter().chain(pages.iter()) {
        println!("generating {:?}", post.path);
        generate_post(&tera, &ctx, &config, &post)?;
    }

    generate_site_page(&tera, &ctx, &config)?;

    Ok(())
}
<|endoftext|>


<commit_before>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<commit_msg>Added doc for GroupingMap::collect<commit_after>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient "group-and-fold" operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
///
// See [`.into_grouping_map()`](../trait.Itertools.html#method.into_grouping_map)
// for more information.
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
where
    I: Iterator<Item = (K, V)>,
    K: Hash + Eq,
{
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// This is the generic way to perform any operations on a `Grouping`.
    /// It's suggested to use it only to implement custom operations when the already provided ones are not enough.
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
    where
        FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
    where
        R: Clone,
        FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
    where
        FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
    /// an instance of `C`. The iteration order is preserved when inserting elements.
    pub fn collect<C>(self) -> HashMap<K, C>
    where
        C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::borrow::Borrow;
use std::collections::HashMap;

use prelude::{NaiveDocument, ProcessedDocument, ExpandableDocument,
  Idf, SmoothingFactor};

/// Unary weighting scheme for IDF. If the corpus contains a document with the
/// term, returns 1, otherwise returns 0.
#[derive(Copy, Clone)] pub struct UnaryIdf;

impl<T> Idf<T> for UnaryIdf where T : NaiveDocument {
  #[inline]
  fn idf<'a, I, K>(term: K, docs: I) -> f64
    where I : Iterator<Item = &'a T>, K : Borrow<T::Term>, T : 'a
  {
    docs.fold(0f64, |_, d| if d.term_exists(term.borrow()) { 1f64 } else { 0f64 })
  }
}

/// Inverse frequency weighting scheme for IDF with a smoothing factor. Used
/// internally as a marker trait.
trait InverseFrequencySmoothedIdfStrategy : SmoothingFactor { }

impl<S, T> Idf<T> for S
  where S : InverseFrequencySmoothedIdfStrategy, T : NaiveDocument
{
  #[inline]
  fn idf<'a, I, K>(term: K, docs: I) -> f64
    where I : Iterator<Item = &'a T>, K : Borrow<T::Term>, T : 'a
  {
    let (num_docs, ttl_docs) = docs.fold(
      (0f64, 0f64),
      |(n, t), d| (if d.term_exists(term.borrow()) { n + 1f64 } else { n }, t + 1f64));
    (S::factor() + (ttl_docs as f64 / num_docs as f64)).ln()
  }
}

/// Inverse frequency weighting scheme for IDF. Computes `log (N / nt)` where `N`
/// is the number of documents, and `nt` is the number of times a term appears in
/// the corpus of documents.
#[derive(Copy, Clone)] pub struct InverseFrequencyIdf;

impl SmoothingFactor for InverseFrequencyIdf {
  fn factor() -> f64 { 0f64 }
}

impl InverseFrequencySmoothedIdfStrategy for InverseFrequencyIdf { }

/// Inverse frequency weighting scheme for IDF. Computes `log (1 + (N / nt))`.
#[derive(Copy, Clone)] pub struct InverseFrequencySmoothIdf;

impl SmoothingFactor for InverseFrequencySmoothIdf {
  fn factor() -> f64 { 1f64 }
}

impl InverseFrequencySmoothedIdfStrategy for InverseFrequencySmoothIdf { }

/// Inverse frequency weighting scheme for IDF. Compute `log (1 + (max nt / nt))`
/// where `nt` is the number of times a term appears in the corpus, and `max nt`
/// returns the most number of times any term appears in the corpus.
#[derive(Copy, Clone)] pub struct InverseFrequencyMaxIdf;

impl<'l, T, E> Idf<T> for InverseFrequencyMaxIdf
  where T : ProcessedDocument<Term = E> + ExpandableDocument<'l>, E : Hash + Eq + 'l
{
  #[inline]
  fn idf<'a, I, K>(term: K, docs: I) -> f64
    where I : Iterator<Item = &'a T>, K : Borrow<T::Term>, T : 'a
  {
    let mut counts: HashMap<&T::Term, usize> = HashMap::new();
    let num_docs = docs.fold(0, |n, d|
      {
        for t in d.terms() { counts.insert(t, 0); }

        if d.term_exists(term.borrow()) { n + 1 } else { n }
      });
    let max = *counts.values().max().unwrap_or(&1);

    (1f64 + (max as f64 / num_docs as f64)).ln()
  }
}

#[test]
fn idf_wiki_example_tests() {
  let mut docs = Vec::new();

  docs.push(vec![("this", 1), ("is", 1), ("a", 2), ("sample", 1)]);
  docs.push(vec![("this", 1), ("is", 1), ("another", 2), ("example", 3)]);

  assert_eq!(UnaryIdf::idf("this", docs.iter()), 1f64);
  assert_eq!(InverseFrequencyIdf::idf("this", docs.iter()), 0f64);
}<commit_msg>Fix for error E0445<commit_after>use std::hash::Hash;
use std::borrow::Borrow;
use std::collections::HashMap;

use prelude::{NaiveDocument, ProcessedDocument, ExpandableDocument,
  Idf, SmoothingFactor};

/// Unary weighting scheme for IDF. If the corpus contains a document with the
/// term, returns 1, otherwise returns 0.
#[derive(Copy, Clone)] pub struct UnaryIdf;

impl<T> Idf<T> for UnaryIdf where T : NaiveDocument {
  #[inline]
  fn idf<'a, I, K>(term: K, docs: I) -> f64
    where I : Iterator<Item = &'a T>, K : Borrow<T::Term>, T : 'a
  {
    docs.fold(0f64, |_, d| if d.term_exists(term.borrow()) { 1f64 } else { 0f64 })
  }
}

/// Inverse frequency weighting scheme for IDF with a smoothing factor. Used
/// internally as a marker trait.
pub trait InverseFrequencySmoothedIdfStrategy : SmoothingFactor { }

impl<S, T> Idf<T> for S
  where S : InverseFrequencySmoothedIdfStrategy, T : NaiveDocument
{
  #[inline]
  fn idf<'a, I, K>(term: K, docs: I) -> f64
    where I : Iterator<Item = &'a T>, K : Borrow<T::Term>, T : 'a
  {
    let (num_docs, ttl_docs) = docs.fold(
      (0f64, 0f64),
      |(n, t), d| (if d.term_exists(term.borrow()) { n + 1f64 } else { n }, t + 1f64));
    (S::factor() + (ttl_docs as f64 / num_docs as f64)).ln()
  }
}

/// Inverse frequency weighting scheme for IDF. Computes `log (N / nt)` where `N`
/// is the number of documents, and `nt` is the number of times a term appears in
/// the corpus of documents.
#[derive(Copy, Clone)] pub struct InverseFrequencyIdf;

impl SmoothingFactor for InverseFrequencyIdf {
  fn factor() -> f64 { 0f64 }
}

impl InverseFrequencySmoothedIdfStrategy for InverseFrequencyIdf { }

/// Inverse frequency weighting scheme for IDF. Computes `log (1 + (N / nt))`.
#[derive(Copy, Clone)] pub struct InverseFrequencySmoothIdf;

impl SmoothingFactor for InverseFrequencySmoothIdf {
  fn factor() -> f64 { 1f64 }
}

impl InverseFrequencySmoothedIdfStrategy for InverseFrequencySmoothIdf { }

/// Inverse frequency weighting scheme for IDF. Compute `log (1 + (max nt / nt))`
/// where `nt` is the number of times a term appears in the corpus, and `max nt`
/// returns the most number of times any term appears in the corpus.
#[derive(Copy, Clone)] pub struct InverseFrequencyMaxIdf;

impl<'l, T, E> Idf<T> for InverseFrequencyMaxIdf
  where T : ProcessedDocument<Term = E> + ExpandableDocument<'l>, E : Hash + Eq + 'l
{
  #[inline]
  fn idf<'a, I, K>(term: K, docs: I) -> f64
    where I : Iterator<Item = &'a T>, K : Borrow<T::Term>, T : 'a
  {
    let mut counts: HashMap<&T::Term, usize> = HashMap::new();
    let num_docs = docs.fold(0, |n, d|
      {
        for t in d.terms() { counts.insert(t, 0); }

        if d.term_exists(term.borrow()) { n + 1 } else { n }
      });
    let max = *counts.values().max().unwrap_or(&1);

    (1f64 + (max as f64 / num_docs as f64)).ln()
  }
}

#[test]
fn idf_wiki_example_tests() {
  let mut docs = Vec::new();

  docs.push(vec![("this", 1), ("is", 1), ("a", 2), ("sample", 1)]);
  docs.push(vec![("this", 1), ("is", 1), ("another", 2), ("example", 3)]);

  assert_eq!(UnaryIdf::idf("this", docs.iter()), 1f64);
  assert_eq!(InverseFrequencyIdf::idf("this", docs.iter()), 0f64);
}
<|endoftext|>


<commit_before>use crate::error::Error;
use crate::instance::{Instance, RunResult, State, TerminationDetails};
use crate::val::{UntypedRetVal, Val};
use crate::vmctx::{Vmctx, VmctxInternal};
use std::any::Any;
use std::future::Future;
use std::pin::Pin;

/// This is the same type defined by the `futures` library, but we don't need the rest of the
/// library for this purpose.
type LocalBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;

/// A unique type that wraps a boxed future with a boxed return value.
///
/// Type and lifetime guarantees are maintained by `Vmctx::block_on` and `Instance::run_async`. The
/// user never sees this type.
struct YieldedFuture(LocalBoxFuture<'static, ResumeVal>);

/// A unique type for a boxed return value. The user never sees this type.
struct ResumeVal(Box<dyn Any + Send + 'static>);

impl Vmctx {
    /// Block on the result of an `async` computation from an instance run by `Instance::run_async`.
    ///
    /// Lucet hostcalls are synchronous `extern "C" fn` functions called from WebAssembly. In that
    /// context, we cannot use `.await` directly because the hostcall is not `async`. While we could
    /// block on an executor using `futures::executor::block_on` or
    /// `tokio::runtime::Runtime::block_on`, that has two drawbacks:
    ///
    /// - If the Lucet instance was originally invoked from an async context, trying to block on the
    ///   same runtime will fail if the executor cannot be nested (all executors we know of have this
    ///   restriction).
    ///
    /// - The current OS thread would be blocked on the result of the computation, rather than being
    ///   able to run other async tasks while awaiting. This means an application will need more
    ///   threads than otherwise would be necessary.
    ///
    /// Instead, this block_on operator is designed to work only when called within an invocation
    /// of [`Instance::run_async`]. The `run_async` method executes instance code within a
    /// trampoline, itself running within an async context, making it possible to temporarily pause
    /// guest execution, jump back to the trampoline, and await there. The future given to block_on
    /// is in passed back to that trampoline, and runs on the same runtime that invoked
    /// `run_async`, avoiding problems of nesting, and allowing the current OS thread to continue
    /// performing other async work.
    ///
    /// Note that this method may only be used if `Instance::run_async` was used to run the VM,
    /// otherwise it will terminate the instance with `TerminationDetails::AwaitNeedsAsync`.
    pub fn block_on<'a, R>(&'a self, f: impl Future<Output = R> + 'a) -> R
    where
        R: Any + Send + 'static,
    {
        // Die if we aren't in Instance::run_async
        match self.instance().state {
            State::Running { async_context } => {
                if !async_context {
                    panic!(TerminationDetails::AwaitNeedsAsync)
                }
            }
            _ => unreachable!("Access to vmctx implies instance is Running"),
        }
        // Wrap the Output of `f` as a boxed ResumeVal. Then, box the entire
        // async computation.
        let f = Box::pin(async move { ResumeVal(Box::new(f.await)) });
        // Change the lifetime of the async computation from `'a` to `'static.
        // We need to lie about this lifetime so that `YieldedFuture` may impl
        // `Any` and be passed through the yield. `Instance::run_async`
        // rehydrates this lifetime to be at most as long as the Vmctx's `'a`.
        // This is safe because the stack frame that `'a` is tied to gets
        // frozen in place as part of `self.yield_val_expecting_val`.
        let f = unsafe {
            std::mem::transmute::<LocalBoxFuture<'a, ResumeVal>, LocalBoxFuture<'static, ResumeVal>>(
                f,
            )
        };
        // Wrap the computation in `YieldedFuture` so that
        // `Instance::run_async` can catch and run it.  We will get the
        // `ResumeVal` we applied to `f` above.
        let ResumeVal(v) = self.yield_val_expecting_val(YieldedFuture(f));
        // We may now downcast and unbox the returned Box<dyn Any> into an `R`
        // again.
        *v.downcast().expect("run_async broke invariant")
    }
}

impl Instance {
    /// Run a WebAssembly function with arguments in the guest context at the given entrypoint.
    ///
    /// This method is similar to `Instance::run()`, but allows the Wasm program to invoke hostcalls
    /// that use `Vmctx::block_on` and provides the trampoline that `.await`s those futures on
    /// behalf of the guest.
    ///
    /// # `Vmctx` Restrictions
    ///
    /// This method permits the use of `Vmctx::block_on`, but disallows all other uses of `Vmctx::
    /// yield_val_expecting_val` and family (`Vmctx::yield_`, `Vmctx::yield_expecting_val`,
    /// `Vmctx::yield_val`).
    ///
    /// # Blocking thread
    ///
    /// The `wrap_blocking` argument is a function that is called with a closure that runs the Wasm
    /// program. Since Wasm may execute for an arbitrarily long time without `await`ing, we need to
    /// make sure that it runs on a thread that is allowed to block.
    ///
    /// This argument is designed with [`tokio::task::block_in_place`][tokio] in mind. The odd type
    /// is a concession to the fact that we don't have rank 2 types in Rust, and so must fall back
    /// to trait objects in order to be able to take an argument that is itself a function that
    /// takes a closure.
    ///
    /// In order to provide an appropriate function, you may have to wrap the library function in
    /// another closure so that the types are compatible. For example:
    ///
    /// ```no_run
    /// # async fn f() {
    /// # let instance: lucet_runtime_internals::instance::InstanceHandle = unimplemented!();
    /// fn block_in_place<F, R>(f: F) -> R
    /// where
    ///     F: FnOnce() -> R,
    /// {
    ///     // ...
    ///     # f()
    /// }
    ///
    /// instance.run_async("entrypoint", &[], |f| block_in_place(f)).await.unwrap();
    /// # }
    /// ```
    ///
    /// [tokio]: https://docs.rs/tokio/0.2.21/tokio/task/fn.block_in_place.html
    pub async fn run_async<'a, F>(
        &'a mut self,
        entrypoint: &'a str,
        args: &'a [Val],
        wrap_blocking: F,
    ) -> Result<UntypedRetVal, Error>
    where
        F: Fn(&mut (dyn FnMut() -> Result<RunResult, Error>)) -> Result<RunResult, Error>,
    {
        if self.is_yielded() {
            return Err(Error::Unsupported(
                "cannot run_async a yielded instance".to_owned(),
            ));
        }

        // Store the ResumeVal here when we get it.
        let mut resume_val: Option<ResumeVal> = None;
        loop {
            // Run the WebAssembly program
            let run_result = wrap_blocking(&mut || {
                if self.is_yielded() {
                    // A previous iteration of the loop stored the ResumeVal in
                    // `resume_val`, send it back to the guest ctx and continue
                    // running:
                    self.resume_with_val_impl(
                        resume_val
                            .take()
                            .expect("is_yielded implies resume_value is some"),
                        true,
                    )
                } else {
                    // This is the first iteration, call the entrypoint:
                    let func = self.module.get_export_func(entrypoint)?;
                    self.run_func(func, args, true)
                }
            })?;
            match run_result {
                RunResult::Returned(rval) => {
                    // Finished running, return UntypedReturnValue
                    return Ok(rval);
                }
                RunResult::Yielded(yval) => {
                    // Check if the yield came from Vmctx::block_on:
                    if yval.is::<YieldedFuture>() {
                        let YieldedFuture(future) = *yval.downcast::<YieldedFuture>().unwrap();
                        // Rehydrate the lifetime from `'static` to `'a`, which
                        // is morally the same lifetime as was passed into
                        // `Vmctx::block_on`.
                        let future = future as LocalBoxFuture<'a, ResumeVal>;
                        // await on the computation. Store its result in
                        // `resume_val`.
                        resume_val = Some(future.await);
                        // Now we want to `Instance::resume_with_val` and start
                        // this cycle over.
                        continue;
                    } else {
                        // Any other yielded value is not supported - die with an error.
                        return Err(Error::Unsupported(
                            "cannot yield anything besides a future in Instance::run_async"
                                .to_owned(),
                        ));
                    }
                }
            }
        }
    }
}
<commit_msg>require that the future argument to `block_on` be `Send`<commit_after>use crate::error::Error;
use crate::instance::{InstanceHandle, RunResult, State, TerminationDetails};
use crate::val::{UntypedRetVal, Val};
use crate::vmctx::{Vmctx, VmctxInternal};
use std::any::Any;
use std::future::Future;
use std::pin::Pin;

/// This is the same type defined by the `futures` library, but we don't need the rest of the
/// library for this purpose.
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

/// A unique type that wraps a boxed future with a boxed return value.
///
/// Type and lifetime guarantees are maintained by `Vmctx::block_on` and `Instance::run_async`. The
/// user never sees this type.
struct YieldedFuture(BoxFuture<'static, ResumeVal>);

/// A unique type for a boxed return value. The user never sees this type.
pub struct ResumeVal(Box<dyn Any + Send + 'static>);

unsafe impl Send for ResumeVal {}

impl Vmctx {
    /// Block on the result of an `async` computation from an instance run by `Instance::run_async`.
    ///
    /// Lucet hostcalls are synchronous `extern "C" fn` functions called from WebAssembly. In that
    /// context, we cannot use `.await` directly because the hostcall is not `async`. While we could
    /// block on an executor using `futures::executor::block_on` or
    /// `tokio::runtime::Runtime::block_on`, that has two drawbacks:
    ///
    /// - If the Lucet instance was originally invoked from an async context, trying to block on the
    ///   same runtime will fail if the executor cannot be nested (all executors we know of have this
    ///   restriction).
    ///
    /// - The current OS thread would be blocked on the result of the computation, rather than being
    ///   able to run other async tasks while awaiting. This means an application will need more
    ///   threads than otherwise would be necessary.
    ///
    /// Instead, this block_on operator is designed to work only when called within an invocation
    /// of [`Instance::run_async`]. The `run_async` method executes instance code within a
    /// trampoline, itself running within an async context, making it possible to temporarily pause
    /// guest execution, jump back to the trampoline, and await there. The future given to block_on
    /// is in passed back to that trampoline, and runs on the same runtime that invoked
    /// `run_async`, avoiding problems of nesting, and allowing the current OS thread to continue
    /// performing other async work.
    ///
    /// Note that this method may only be used if `Instance::run_async` was used to run the VM,
    /// otherwise it will terminate the instance with `TerminationDetails::AwaitNeedsAsync`.
    pub fn block_on<'a, R>(&'a self, f: impl Future<Output = R> + Send + 'a) -> R
    where
        R: Any + Send + 'static,
    {
        // Die if we aren't in Instance::run_async
        match self.instance().state {
            State::Running { async_context } => {
                if !async_context {
                    panic!(TerminationDetails::AwaitNeedsAsync)
                }
            }
            _ => unreachable!("Access to vmctx implies instance is Running"),
        }
        // Wrap the Output of `f` as a boxed ResumeVal. Then, box the entire
        // async computation.
        let f = Box::pin(async move { ResumeVal(Box::new(f.await)) });
        // Change the lifetime of the async computation from `'a` to `'static.
        // We need to lie about this lifetime so that `YieldedFuture` may impl
        // `Any` and be passed through the yield. `Instance::run_async`
        // rehydrates this lifetime to be at most as long as the Vmctx's `'a`.
        // This is safe because the stack frame that `'a` is tied to gets
        // frozen in place as part of `self.yield_val_expecting_val`.
        let f = unsafe {
            std::mem::transmute::<BoxFuture<'a, ResumeVal>, BoxFuture<'static, ResumeVal>>(f)
        };
        // Wrap the computation in `YieldedFuture` so that
        // `Instance::run_async` can catch and run it.  We will get the
        // `ResumeVal` we applied to `f` above.
        let ResumeVal(v) = self.yield_val_expecting_val(YieldedFuture(f));
        // We may now downcast and unbox the returned Box<dyn Any> into an `R`
        // again.
        *v.downcast().expect("run_async broke invariant")
    }
}

pub enum Bounce<'a> {
    Done(UntypedRetVal),
    More(BoxFuture<'a, ResumeVal>),
}

impl InstanceHandle {
    /// Run a WebAssembly function with arguments in the guest context at the given entrypoint.
    ///
    /// This method is similar to `Instance::run()`, but allows the Wasm program to invoke hostcalls
    /// that use `Vmctx::block_on` and provides the trampoline that `.await`s those futures on
    /// behalf of the guest.
    ///
    /// # `Vmctx` Restrictions
    ///
    /// This method permits the use of `Vmctx::block_on`, but disallows all other uses of `Vmctx::
    /// yield_val_expecting_val` and family (`Vmctx::yield_`, `Vmctx::yield_expecting_val`,
    /// `Vmctx::yield_val`).
    ///
    /// # Blocking thread
    ///
    /// The `wrap_blocking` argument is a function that is called with a closure that runs the Wasm
    /// program. Since Wasm may execute for an arbitrarily long time without `await`ing, we need to
    /// make sure that it runs on a thread that is allowed to block.
    ///
    /// This argument is designed with [`tokio::task::block_in_place`][tokio] in mind. The odd type
    /// is a concession to the fact that we don't have rank 2 types in Rust, and so must fall back
    /// to trait objects in order to be able to take an argument that is itself a function that
    /// takes a closure.
    ///
    /// In order to provide an appropriate function, you may have to wrap the library function in
    /// another closure so that the types are compatible. For example:
    ///
    /// ```no_run
    /// # async fn f() {
    /// # let instance: lucet_runtime_internals::instance::InstanceHandle = unimplemented!();
    /// fn block_in_place<F, R>(f: F) -> R
    /// where
    ///     F: FnOnce() -> R,
    /// {
    ///     // ...
    ///     # f()
    /// }
    ///
    /// instance.run_async("entrypoint", &[], |f| block_in_place(f)).await.unwrap();
    /// # }
    /// ```
    ///
    /// [tokio]: https://docs.rs/tokio/0.2.21/tokio/task/fn.block_in_place.html
    pub async fn run_async<'a, F>(
        &'a mut self,
        entrypoint: &'a str,
        args: &'a [Val],
        wrap_blocking: F,
    ) -> Result<UntypedRetVal, Error>
    where
        F: for<'b> Fn(&mut (dyn FnMut() -> Result<Bounce<'b>, Error>)) -> Result<Bounce<'b>, Error>,
    {
        if self.is_yielded() {
            return Err(Error::Unsupported(
                "cannot run_async a yielded instance".to_owned(),
            ));
        }

        // Store the ResumeVal here when we get it.
        let mut resume_val: Option<ResumeVal> = None;
        loop {
            // Run the WebAssembly program
            let bounce = wrap_blocking(&mut || {
                let run_result = if self.is_yielded() {
                    // A previous iteration of the loop stored the ResumeVal in
                    // `resume_val`, send it back to the guest ctx and continue
                    // running:
                    self.resume_with_val_impl(
                        resume_val
                            .take()
                            .expect("is_yielded implies resume_value is some"),
                        true,
                    )
                } else {
                    // This is the first iteration, call the entrypoint:
                    let func = self.module.get_export_func(entrypoint)?;
                    self.run_func(func, args, true)
                };
                match run_result? {
                    RunResult::Returned(rval) => {
                        // Finished running, return UntypedReturnValue
                        return Ok(Bounce::Done(rval));
                    }
                    RunResult::Yielded(yval) => {
                        // Check if the yield came from Vmctx::block_on:
                        if yval.is::<YieldedFuture>() {
                            let YieldedFuture(future) = *yval.downcast::<YieldedFuture>().unwrap();
                            // Rehydrate the lifetime from `'static` to `'a`, which
                            // is morally the same lifetime as was passed into
                            // `Vmctx::block_on`.
                            Ok(Bounce::More(future as BoxFuture<'a, ResumeVal>))
                        } else {
                            // Any other yielded value is not supported - die with an error.
                            Err(Error::Unsupported(
                                "cannot yield anything besides a future in Instance::run_async"
                                    .to_owned(),
                            ))
                        }
                    }
                }
            })?;
            match bounce {
                Bounce::Done(rval) => return Ok(rval),
                Bounce::More(fut) => {
                    // await on the computation. Store its result in
                    // `resume_val`.
                    resume_val = Some(fut.await);
                    // Now we want to `Instance::resume_with_val` and start
                    // this cycle over.
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use latch::Latch;
#[cfg(feature = "nightly")]
use std::any::Any;
#[cfg(feature = "nightly")]
use std::panic::{self, AssertUnwindSafe};
use std::cell::UnsafeCell;
use std::mem;

enum JobResult<T> {
    None,
    Ok(T),
    #[cfg(feature = "nightly")]
    Panic(Box<Any + Send>),
}

/// A `Job` is used to advertise work for other threads that they may
/// want to steal. In accordance with time honored tradition, jobs are
/// arranged in a deque, so that thieves can take from the top of the
/// deque while the main worker manages the bottom of the deque. This
/// deque is managed by the `thread_pool` module.
pub trait Job {
    unsafe fn execute(&self, mode: JobMode);
}

pub enum JobMode {
    Execute,
    Abort,
}

/// Effectively a Job trait object. Each JobRef **must** be executed
/// exactly once, or else data may leak.
///
/// Internally, we store the job's data in a `*const ()` pointer.  The
/// true type is something like `*const StackJob<...>`, but we hide
/// it. We also carry the "execute fn" from the `Job` trait.
#[derive(Copy, Clone)]
pub struct JobRef {
    pointer: *const (),
    execute_fn: unsafe fn(*const (), mode: JobMode),
}

unsafe impl Send for JobRef {}
unsafe impl Sync for JobRef {}

impl JobRef {
    unsafe fn new<T>(data: *const T) -> JobRef
        where T: Job
    {
        let fn_ptr: unsafe fn(&T, JobMode) = <T as Job>::execute;

        // erase types:
        let fn_ptr: unsafe fn(*const (), JobMode) = mem::transmute(fn_ptr);
        let pointer = data as *const ();

        JobRef { pointer: pointer, execute_fn: fn_ptr }
    }

    #[inline]
    pub unsafe fn execute(&self, mode: JobMode) {
        (self.execute_fn)(self.pointer, mode)
    }
}

/// A job that will be owned by a stack slot. This means that when it
/// executes it need not free any heap data, the cleanup occurs when
/// the stack frame is later popped.
pub struct StackJob<L: Latch, F, R> {
    pub latch: L,
    func: UnsafeCell<Option<F>>,
    result: UnsafeCell<JobResult<R>>,
}

impl<L: Latch, F, R> StackJob<L, F, R>
    where F: FnOnce() -> R
{
    pub fn new(func: F, latch: L) -> StackJob<L, F, R> {
        StackJob {
            latch: latch,
            func: UnsafeCell::new(Some(func)),
            result: UnsafeCell::new(JobResult::None),
        }
    }

    pub unsafe fn as_job_ref(&self) -> JobRef {
        JobRef::new(self)
    }

    pub unsafe fn run_inline(self) -> R {
        self.func.into_inner().unwrap()()
    }

    #[cfg(not(feature = "nightly"))]
    pub unsafe fn into_result(self) -> R {
        match self.result.into_inner() {
            JobResult::None => panic!("job function panicked"),
            JobResult::Ok(x) => x,
        }
    }

    #[cfg(feature = "nightly")]
    pub unsafe fn into_result(self) -> R {
        match self.result.into_inner() {
            JobResult::None => unreachable!(),
            JobResult::Ok(x) => x,
            JobResult::Panic(x) => panic::resume_unwind(x),
        }
    }

    #[cfg(not(feature = "nightly"))]
    fn run_result(func: F) -> JobResult<R> {
        JobResult::Ok(func())
    }

    #[cfg(feature = "nightly")]
    fn run_result(func: F) -> JobResult<R> {
        // We assert that func is unwind-safe since it doesn't touch any of
        // our data and we will be propagating the panic back to the user at
        // the join() call.
        match panic::catch_unwind(AssertUnwindSafe(func)) {
            Ok(x) => JobResult::Ok(x),
            Err(x) => JobResult::Panic(x),
        }
    }
}

impl<L: Latch, F, R> Job for StackJob<L, F, R>
    where F: FnOnce() -> R
{
    unsafe fn execute(&self, mode: JobMode) {
        match mode {
            JobMode::Execute => {
                // Use a guard here to ensure that the latch is always set, even if
                // the function panics.
                struct PanicGuard<'a, L: Latch + 'a>(&'a L);
                impl<'a, L: Latch> Drop for PanicGuard<'a, L> {
                    fn drop(&mut self) {
                        self.0.set();
                    }
                }

                let _guard = PanicGuard(&self.latch);
                let func = (*self.func.get()).take().unwrap();
                (*self.result.get()) = Self::run_result(func);
            }
            JobMode::Abort => {
                self.latch.set();
            }
        }
    }
}
<commit_msg>modify trait to take `self` by unsafe ref<commit_after>use latch::Latch;
#[cfg(feature = "nightly")]
use std::any::Any;
#[cfg(feature = "nightly")]
use std::panic::{self, AssertUnwindSafe};
use std::cell::UnsafeCell;
use std::mem;

enum JobResult<T> {
    None,
    Ok(T),
    #[cfg(feature = "nightly")]
    Panic(Box<Any + Send>),
}

/// A `Job` is used to advertise work for other threads that they may
/// want to steal. In accordance with time honored tradition, jobs are
/// arranged in a deque, so that thieves can take from the top of the
/// deque while the main worker manages the bottom of the deque. This
/// deque is managed by the `thread_pool` module.
pub trait Job {
    unsafe fn execute(this: *const Self, mode: JobMode);
}

pub enum JobMode {
    Execute,
    Abort,
}

/// Effectively a Job trait object. Each JobRef **must** be executed
/// exactly once, or else data may leak.
///
/// Internally, we store the job's data in a `*const ()` pointer.  The
/// true type is something like `*const StackJob<...>`, but we hide
/// it. We also carry the "execute fn" from the `Job` trait.
#[derive(Copy, Clone)]
pub struct JobRef {
    pointer: *const (),
    execute_fn: unsafe fn(*const (), mode: JobMode),
}

unsafe impl Send for JobRef {}
unsafe impl Sync for JobRef {}

impl JobRef {
    unsafe fn new<T>(data: *const T) -> JobRef
        where T: Job
    {
        let fn_ptr: unsafe fn(*const T, JobMode) = <T as Job>::execute;

        // erase types:
        let fn_ptr: unsafe fn(*const (), JobMode) = mem::transmute(fn_ptr);
        let pointer = data as *const ();

        JobRef { pointer: pointer, execute_fn: fn_ptr }
    }

    #[inline]
    pub unsafe fn execute(&self, mode: JobMode) {
        (self.execute_fn)(self.pointer, mode)
    }
}

/// A job that will be owned by a stack slot. This means that when it
/// executes it need not free any heap data, the cleanup occurs when
/// the stack frame is later popped.
pub struct StackJob<L: Latch, F, R> {
    pub latch: L,
    func: UnsafeCell<Option<F>>,
    result: UnsafeCell<JobResult<R>>,
}

impl<L: Latch, F, R> StackJob<L, F, R>
    where F: FnOnce() -> R
{
    pub fn new(func: F, latch: L) -> StackJob<L, F, R> {
        StackJob {
            latch: latch,
            func: UnsafeCell::new(Some(func)),
            result: UnsafeCell::new(JobResult::None),
        }
    }

    pub unsafe fn as_job_ref(&self) -> JobRef {
        JobRef::new(self)
    }

    pub unsafe fn run_inline(self) -> R {
        self.func.into_inner().unwrap()()
    }

    #[cfg(not(feature = "nightly"))]
    pub unsafe fn into_result(self) -> R {
        match self.result.into_inner() {
            JobResult::None => panic!("job function panicked"),
            JobResult::Ok(x) => x,
        }
    }

    #[cfg(feature = "nightly")]
    pub unsafe fn into_result(self) -> R {
        match self.result.into_inner() {
            JobResult::None => unreachable!(),
            JobResult::Ok(x) => x,
            JobResult::Panic(x) => panic::resume_unwind(x),
        }
    }

    #[cfg(not(feature = "nightly"))]
    fn run_result(func: F) -> JobResult<R> {
        JobResult::Ok(func())
    }

    #[cfg(feature = "nightly")]
    fn run_result(func: F) -> JobResult<R> {
        // We assert that func is unwind-safe since it doesn't touch any of
        // our data and we will be propagating the panic back to the user at
        // the join() call.
        match panic::catch_unwind(AssertUnwindSafe(func)) {
            Ok(x) => JobResult::Ok(x),
            Err(x) => JobResult::Panic(x),
        }
    }
}

impl<L: Latch, F, R> Job for StackJob<L, F, R>
    where F: FnOnce() -> R
{
    unsafe fn execute(this: *const Self, mode: JobMode) {
        let this = &*this;
        match mode {
            JobMode::Execute => {
                // Use a guard here to ensure that the latch is always set, even if
                // the function panics.
                struct PanicGuard<'a, L: Latch + 'a>(&'a L);
                impl<'a, L: Latch> Drop for PanicGuard<'a, L> {
                    fn drop(&mut self) {
                        self.0.set();
                    }
                }

                let _guard = PanicGuard(&this.latch);
                let func = (*this.func.get()).take().unwrap();
                (*this.result.get()) = Self::run_result(func);
            }
            JobMode::Abort => {
                this.latch.set();
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate byteorder;
extern crate uuid;

use std::option::Option;
use std::cmp::Ordering;
use std::io::Write;
use std::io::Read;
use std::io;
use std::net::TcpStream;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::thread;
use std::thread::{JoinHandle, sleep_ms, Thread};
use std::sync::{Mutex, Condvar, Arc};
use std::sync::mpsc::channel;
use std::sync::mpsc::{Receiver, Sender};

use byteorder::{BigEndian, WriteBytesExt};
use byteorder::ReadBytesExt;
use uuid::Uuid;

pub mod constants;
use constants::*;

#[test]
fn constructor() {
    let c = Connection::new("localhost", 4730);

    assert!(c.host == "localhost");
    assert!(c.port == 4730);
    assert!(c.state == ConnectionState::INIT);

    let now = time::now_utc();
    match c.state_time {
        Some(c_time) => {
            let result = now.cmp(&c_time);  // Could fail if no nanoseconds
            assert_eq!(Ordering::Greater, result);
        },
        None => assert!(false)
    }
}

#[test]
fn change_state() {
    let mut c = Connection::new("localhost", 4730);

    c.change_state(ConnectionState::INIT);
    assert!(c.state == ConnectionState::INIT);
}

#[test]
fn packet_constructor() {
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    assert!(p.code == PacketCode::REQ);
    assert!(p.ptype == ECHO_REQ);
    assert!(p.data.len() == 1);
}

#[test]
#[should_panic]
fn send_packet() {
    let mut conn = Connection::new("localost", 4730);
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    conn.sendPacket(p)
}

#[test]
#[should_panic]
fn echo() {
    let mut test: Vec<u8> = Vec::new();
    test.extend("abc123".to_string().bytes());
    let mut conn = Connection::new("localhost", 4730);
    let result = String::from_utf8(conn.echo(test, 0)).unwrap();
    assert_eq!("abc123", result);
    let mut test2: Vec<u8> = Vec::new();
    let mut output = String::from_utf8(conn.echo(test2, 0)).unwrap();
    println!("UUID = {}", output);
}

#[test]
fn bcs_constructor() {
    let bcs = BaseClientServer::new("clientid".to_string().into_bytes());
}

#[derive(PartialEq)]
enum ConnectionState {
    INIT,
}

struct Connection {
    host: String,
    port: u16,
    conn: Option<TcpStream>,
    connect_time: Option<time::Tm>,
    state: ConnectionState,
    state_time: Option<time::Tm>,
    echo_conditions: HashMap<Vec<u8>, Arc<(Mutex<bool>, Condvar)>>,
}

struct Packet {
    code: PacketCode,
    ptype: u32,
    data: Box<[u8]>,
}

impl Connection {
    fn new(host: &str, port: u16) -> Connection {
        let mut c = Connection {
            host: host.to_string(),
            port: port,
            conn: None,
            connect_time: None,
            state: ConnectionState::INIT,
            state_time: None,
            echo_conditions: HashMap::new(),
        };
        c.change_state(ConnectionState::INIT);
        return c
    }

    fn change_state(&mut self, state: ConnectionState) {
        self.state_time = Some(time::now_utc());
        self.state = state;
    }

    fn connect(&mut self) -> io::Result<()> {
        match self.conn {
            None => {
                self.conn = Some(try!(TcpStream::connect((&self.host as &str, self.port))));
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
        return Ok(());
    }

    fn disconnect(&mut self) {
        match self.conn {
            Some(_) => self.conn = None,
            None => { /* log debug "already disconnected" */ },
        }
    }

    fn reconnect(&mut self) -> io::Result<()> {
        self.disconnect();
        try!(self.connect());
        return Ok(());
    }

    fn sendPacket(&mut self, packet: Packet) {
        match self.conn {
            Some(ref mut c) => {
                match packet.code {
                    PacketCode::REQ => { c.write(&REQ).unwrap(); }
                    PacketCode::RES => { c.write(&RES).unwrap(); }
                }
                c.write_u32::<BigEndian>(packet.ptype);
                c.write_u32::<BigEndian>(packet.data.len() as u32).unwrap();
                c.write_all(&packet.data).unwrap();
            },
            None => panic!("Attempted to send packet on disconnected socket")
        }
    }

    fn _code_from_vec(code: Vec<u8>) -> Result<PacketCode, &'static str> {
        if code[..] == REQ {
            return Ok(PacketCode::REQ);
        } else if code[..] == RES {
            return Ok(PacketCode::RES);
        }
        return Err("Invalid packet code");
    }

    fn readPacket(&mut self) -> Packet {
        match self.conn {
            Some(ref mut c) => {
                let mut code: Vec<u8> = Vec::new();
                {
                    let mut codestream = c.take(4);
                    codestream.read_to_end(&mut code).unwrap();
                }
                let code: PacketCode = Connection::_code_from_vec(code).unwrap();
                let ptype   = c.read_u32::<BigEndian>().unwrap();
                let datalen = c.read_u32::<BigEndian>().unwrap();
                let mut datastream = c.take(datalen as u64);
                let mut buf: Vec<u8> = Vec::new();
                datastream.read_to_end(&mut buf).unwrap();
                return Packet {
                    code: code,
                    ptype: ptype,
                    data: buf.into_boxed_slice(),
                }
            },
            None => panic!("Attempted to read packet on disconnected socket")
        }
    }

    fn echo(&mut self, mut data: Vec<u8>, timeout: u32) -> Vec<u8> {
        if data.len() == 0 {
            data.extend(Uuid::new_v4().to_simple_string().bytes());
        }
        let lock_cond = Arc::new((Mutex::new(false), Condvar::new()));
        let &(ref lock, ref cond) = &*lock_cond;
        let mut handled_echo = lock.lock().unwrap();
        self.sendEchoReq(data.clone());
        self.echo_conditions.insert(data.clone(), lock_cond.clone());
        if !*cond.wait_timeout_ms(handled_echo, timeout * 1000).unwrap().0 {
            panic!("Timed out waiting for response from echo.");
        };
        self.echo_conditions.remove(&data);
        data
    }

    fn sendEchoReq(&mut self, mut data: Vec<u8>) {
        let p = Packet::new(PacketCode::REQ, ECHO_REQ, data.into_boxed_slice());
        self.sendPacket(p)
    }

    fn handleEchoRes(&mut self, mut data: Vec<u8>) {
        if let Some(mutexlock) = self.echo_conditions.get_mut(&data) {
            let lock = &mutexlock.0;
            let cond = &mutexlock.1;
            let mut handled_echo = lock.lock().unwrap();
            *handled_echo = true;

            cond.notify_one();
        }
    }
}

struct BaseClientServer<'a> {
    client_id: Vec<u8>,
    running: bool,
    active_connections: HashMap<(&'a String, u16), Arc<Mutex<Box<Connection>>>>,
    host_io: (Sender<Arc<Mutex<Box<(&'a String, u16)>>>>, Receiver<Arc<Mutex<Box<(&'a String, u16)>>>>),
    conn_io: (Sender<Arc<Mutex<Box<Connection>>>>, Receiver<Arc<Mutex<Box<Connection>>>>),
}

impl <'a>BaseClientServer<'a> {

    fn new(client_id: Vec<u8>) -> BaseClientServer<'a> {
        BaseClientServer {
            client_id: client_id,
            running: true,
            active_connections: HashMap::new(),
            host_io: channel(),
            conn_io: channel(),
        }
    }

    /*
    fn start(mut self) {
        let mut bcs_poll_handle = Arc::new(Mutex::new(&mut self));
        let mut bcs_conn_handle = bcs_poll_handle.clone();
        let poll_join_handle = Some(thread::scoped(move || BaseClientServer::_doPollLoop(bcs_poll_handle)));
        let connect_join_handle = Some(thread::scoped(move || BaseClientServer::_doConnectLoop(bcs_conn_handle)));
        // implicit join
    }
    */

    fn connectionManager(&'a mut self) {
        /* Run as a dedicated thread to manage the list of active/inactive connections */
        let (_, ref mut rx) = self.host_io;
        let ac = &mut self.active_connections;
        while self.running {
            let container = rx.recv().unwrap();
            let (host, port) = **container.lock().unwrap();
            let mut insert = false;
            let conn = match ac.get(&(host, port)) {
                Some(conn) => {
                    let mut real_conn = conn.lock().unwrap();
                    real_conn.reconnect().unwrap();
                    conn.clone()
                },
                None => {
                    let conn: Arc<Mutex<Box<Connection>>> = Arc::new(Mutex::new(Box::new(Connection::new(&host, port)))).clone();
                    {
                        let mut real_conn = conn.lock().unwrap();
                        real_conn.connect().unwrap();
                    }
                    insert = true;
                    conn
                }
            };
            if insert {
                ac.insert((host, port), conn.clone());
            }
        }
        for (_, conn) in ac.iter() {
            let mut conn = conn.lock().unwrap();
            conn.disconnect();
        }
    }

    fn addServer(&'a self, host: &'a String, port: u16) {
        let (ref tx, _) = self.host_io;
        tx.send(Arc::new(Mutex::new(Box::new((host, port)))));
    }

    fn pollingManager(&'a self) {
        let (_, ref rx) = self.conn_io;
        let (ref tx, _) = self.host_io;
        let mut threads: Vec<JoinHandle<()>> = Vec::new();
        while self.running {
            let conn = rx.recv().unwrap();
            // poll this conn
            threads.push(thread::spawn(move || {
                let mut conn = conn.lock().unwrap();
                let p = conn.readPacket();
                // handle packet
            }));
        };
        // scoped threads all joined here
        for mut thread in threads {
            thread.join();
        }
    }
}

impl PartialEq for Packet {
    fn eq(&self, other: &Packet) -> bool {
        self.code == other.code &&
        self.ptype == other.ptype &&
        self.data == other.data
    }
}

impl Packet {
    fn new(code: PacketCode, ptype: u32, data: Box<[u8]>) -> Packet {
        Packet {
            code: code,
            ptype: ptype,
            data: data,
        }
    }
}
<commit_msg>Send connections to polling manager<commit_after>extern crate time;
extern crate byteorder;
extern crate uuid;

use std::option::Option;
use std::cmp::Ordering;
use std::io::Write;
use std::io::Read;
use std::io;
use std::net::TcpStream;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::thread;
use std::thread::{JoinHandle, sleep_ms, Thread};
use std::sync::{Mutex, Condvar, Arc};
use std::sync::mpsc::channel;
use std::sync::mpsc::{Receiver, Sender};

use byteorder::{BigEndian, WriteBytesExt};
use byteorder::ReadBytesExt;
use uuid::Uuid;

pub mod constants;
use constants::*;

#[test]
fn constructor() {
    let c = Connection::new("localhost", 4730);

    assert!(c.host == "localhost");
    assert!(c.port == 4730);
    assert!(c.state == ConnectionState::INIT);

    let now = time::now_utc();
    match c.state_time {
        Some(c_time) => {
            let result = now.cmp(&c_time);  // Could fail if no nanoseconds
            assert_eq!(Ordering::Greater, result);
        },
        None => assert!(false)
    }
}

#[test]
fn change_state() {
    let mut c = Connection::new("localhost", 4730);

    c.change_state(ConnectionState::INIT);
    assert!(c.state == ConnectionState::INIT);
}

#[test]
fn packet_constructor() {
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    assert!(p.code == PacketCode::REQ);
    assert!(p.ptype == ECHO_REQ);
    assert!(p.data.len() == 1);
}

#[test]
#[should_panic]
fn send_packet() {
    let mut conn = Connection::new("localost", 4730);
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    conn.sendPacket(p)
}

#[test]
#[should_panic]
fn echo() {
    let mut test: Vec<u8> = Vec::new();
    test.extend("abc123".to_string().bytes());
    let mut conn = Connection::new("localhost", 4730);
    let result = String::from_utf8(conn.echo(test, 0)).unwrap();
    assert_eq!("abc123", result);
    let mut test2: Vec<u8> = Vec::new();
    let mut output = String::from_utf8(conn.echo(test2, 0)).unwrap();
    println!("UUID = {}", output);
}

#[test]
fn bcs_constructor() {
    let bcs = BaseClientServer::new("clientid".to_string().into_bytes());
}

#[derive(PartialEq)]
enum ConnectionState {
    INIT,
}

struct Connection {
    host: String,
    port: u16,
    conn: Option<TcpStream>,
    connect_time: Option<time::Tm>,
    state: ConnectionState,
    state_time: Option<time::Tm>,
    echo_conditions: HashMap<Vec<u8>, Arc<(Mutex<bool>, Condvar)>>,
}

struct Packet {
    code: PacketCode,
    ptype: u32,
    data: Box<[u8]>,
}

impl Connection {
    fn new(host: &str, port: u16) -> Connection {
        let mut c = Connection {
            host: host.to_string(),
            port: port,
            conn: None,
            connect_time: None,
            state: ConnectionState::INIT,
            state_time: None,
            echo_conditions: HashMap::new(),
        };
        c.change_state(ConnectionState::INIT);
        return c
    }

    fn change_state(&mut self, state: ConnectionState) {
        self.state_time = Some(time::now_utc());
        self.state = state;
    }

    fn connect(&mut self) -> io::Result<()> {
        match self.conn {
            None => {
                self.conn = Some(try!(TcpStream::connect((&self.host as &str, self.port))));
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
        return Ok(());
    }

    fn disconnect(&mut self) {
        match self.conn {
            Some(_) => self.conn = None,
            None => { /* log debug "already disconnected" */ },
        }
    }

    fn reconnect(&mut self) -> io::Result<()> {
        self.disconnect();
        try!(self.connect());
        return Ok(());
    }

    fn sendPacket(&mut self, packet: Packet) {
        match self.conn {
            Some(ref mut c) => {
                match packet.code {
                    PacketCode::REQ => { c.write(&REQ).unwrap(); }
                    PacketCode::RES => { c.write(&RES).unwrap(); }
                }
                c.write_u32::<BigEndian>(packet.ptype);
                c.write_u32::<BigEndian>(packet.data.len() as u32).unwrap();
                c.write_all(&packet.data).unwrap();
            },
            None => panic!("Attempted to send packet on disconnected socket")
        }
    }

    fn _code_from_vec(code: Vec<u8>) -> Result<PacketCode, &'static str> {
        if code[..] == REQ {
            return Ok(PacketCode::REQ);
        } else if code[..] == RES {
            return Ok(PacketCode::RES);
        }
        return Err("Invalid packet code");
    }

    fn readPacket(&mut self) -> Packet {
        match self.conn {
            Some(ref mut c) => {
                let mut code: Vec<u8> = Vec::new();
                {
                    let mut codestream = c.take(4);
                    codestream.read_to_end(&mut code).unwrap();
                }
                let code: PacketCode = Connection::_code_from_vec(code).unwrap();
                let ptype   = c.read_u32::<BigEndian>().unwrap();
                let datalen = c.read_u32::<BigEndian>().unwrap();
                let mut datastream = c.take(datalen as u64);
                let mut buf: Vec<u8> = Vec::new();
                datastream.read_to_end(&mut buf).unwrap();
                return Packet {
                    code: code,
                    ptype: ptype,
                    data: buf.into_boxed_slice(),
                }
            },
            None => panic!("Attempted to read packet on disconnected socket")
        }
    }

    fn echo(&mut self, mut data: Vec<u8>, timeout: u32) -> Vec<u8> {
        if data.len() == 0 {
            data.extend(Uuid::new_v4().to_simple_string().bytes());
        }
        let lock_cond = Arc::new((Mutex::new(false), Condvar::new()));
        let &(ref lock, ref cond) = &*lock_cond;
        let mut handled_echo = lock.lock().unwrap();
        self.sendEchoReq(data.clone());
        self.echo_conditions.insert(data.clone(), lock_cond.clone());
        if !*cond.wait_timeout_ms(handled_echo, timeout * 1000).unwrap().0 {
            panic!("Timed out waiting for response from echo.");
        };
        self.echo_conditions.remove(&data);
        data
    }

    fn sendEchoReq(&mut self, mut data: Vec<u8>) {
        let p = Packet::new(PacketCode::REQ, ECHO_REQ, data.into_boxed_slice());
        self.sendPacket(p)
    }

    fn handleEchoRes(&mut self, mut data: Vec<u8>) {
        if let Some(mutexlock) = self.echo_conditions.get_mut(&data) {
            let lock = &mutexlock.0;
            let cond = &mutexlock.1;
            let mut handled_echo = lock.lock().unwrap();
            *handled_echo = true;

            cond.notify_one();
        }
    }
}

struct BaseClientServer<'a> {
    client_id: Vec<u8>,
    running: bool,
    active_connections: HashMap<(&'a String, u16), Arc<Mutex<Box<Connection>>>>,
    host_io: (Sender<Arc<Mutex<Box<(&'a String, u16)>>>>, Receiver<Arc<Mutex<Box<(&'a String, u16)>>>>),
    conn_io: (Sender<Arc<Mutex<Box<Connection>>>>, Receiver<Arc<Mutex<Box<Connection>>>>),
}

impl <'a>BaseClientServer<'a> {

    fn new(client_id: Vec<u8>) -> BaseClientServer<'a> {
        BaseClientServer {
            client_id: client_id,
            running: true,
            active_connections: HashMap::new(),
            host_io: channel(),
            conn_io: channel(),
        }
    }

    /*
    fn start(mut self) {
        let mut bcs_poll_handle = Arc::new(Mutex::new(&mut self));
        let mut bcs_conn_handle = bcs_poll_handle.clone();
        let poll_join_handle = Some(thread::scoped(move || BaseClientServer::_doPollLoop(bcs_poll_handle)));
        let connect_join_handle = Some(thread::scoped(move || BaseClientServer::_doConnectLoop(bcs_conn_handle)));
        // implicit join
    }
    */

    fn connectionManager(&'a mut self) {
        /* Run as a dedicated thread to manage the list of active/inactive connections */
        let (_, ref mut rx) = self.host_io;
        let (ref mut tx, _) = self.conn_io;
        let ac = &mut self.active_connections;
        while self.running {
            let container = rx.recv().unwrap();
            let (host, port) = **container.lock().unwrap();
            let mut insert = false;
            let conn = match ac.get(&(host, port)) {
                Some(conn) => {
                    let mut real_conn = conn.lock().unwrap();
                    real_conn.reconnect().unwrap();
                    conn.clone()
                },
                None => {
                    let conn: Arc<Mutex<Box<Connection>>> = Arc::new(Mutex::new(Box::new(Connection::new(&host, port)))).clone();
                    {
                        let mut real_conn = conn.lock().unwrap();
                        real_conn.connect().unwrap();
                    }
                    insert = true;
                    conn
                }
            };
            if insert {
                ac.insert((host, port), conn.clone());
            }
            tx.send(conn.clone());
        }
        for (_, conn) in ac.iter() {
            let mut conn = conn.lock().unwrap();
            conn.disconnect();
        }
    }

    fn addServer(&'a self, host: &'a String, port: u16) {
        let (ref tx, _) = self.host_io;
        tx.send(Arc::new(Mutex::new(Box::new((host, port)))));
    }

    fn pollingManager(&'a self) {
        let (_, ref rx) = self.conn_io;
        let (ref tx, _) = self.host_io;
        let mut threads: Vec<JoinHandle<()>> = Vec::new();
        while self.running {
            let conn = rx.recv().unwrap();
            // poll this conn
            threads.push(thread::spawn(move || {
                let mut conn = conn.lock().unwrap();
                let p = conn.readPacket();
                // handle packet
            }));
        };
        // scoped threads all joined here
        for mut thread in threads {
            thread.join();
        }
    }
}

impl PartialEq for Packet {
    fn eq(&self, other: &Packet) -> bool {
        self.code == other.code &&
        self.ptype == other.ptype &&
        self.data == other.data
    }
}

impl Packet {
    fn new(code: PacketCode, ptype: u32, data: Box<[u8]>) -> Packet {
        Packet {
            code: code,
            ptype: ptype,
            data: data,
        }
    }
}
<|endoftext|>


<commit_before>extern crate num;

extern "C" {
    /// Regularized incomplete beta function.
    fn incbet(a: f64, b: f64, x: f64) -> f64;
    /// Inverse of incomplete beta integral.
    fn incbi(a: f64, b: f64, y: f64) -> f64;
    /// Regularized incomplete gamma integral.
    fn igam(a: f64, x: f64) -> f64;
    /// Complemented incomplete gamma integral.
    fn igamc(a: f64, x: f64) -> f64;
    /// Inverse of complemented incomplete gamma integral.
    fn igami(a: f64, p: f64) -> f64;
    /// Normal distribution function.
    fn ndtr(x: f64) -> f64;
    /// Inverse of Normal distribution function.
    fn ndtri(x: f64) -> f64;
    /// Bessel function of non-integer order.
    fn jv(v: f64, x: f64) -> f64;

    /// Regularized incomplete beta function.
    fn incbetf(a: f32, b: f32, x: f32) -> f32;
    /// Inverse of incomplete beta integral.
    fn incbif(a: f32, b: f32, y: f32) -> f32;
    /// Regularized incomplete gamma integral.
    fn igamf(a: f32, x: f32) -> f32;
    /// Complemented incomplete gamma integral.
    fn igamcf(a: f32, x: f32) -> f32;
    /// Inverse of complemented incomplete gamma integral.
    fn igamif(a: f32, p: f32) -> f32;
    /// Normal distribution function.
    fn ndtrf(x: f32) -> f32;
    /// Inverse of Normal distribution function.
    fn ndtrif(x: f32) -> f32;
    /// Bessel function of non-integer order.
    fn jvf(v: f32, x: f32) -> f32;
}

/// Special functions on primitive floating point numbers.
/// These are essential for most statistical applications.
pub trait FloatSpecial {
    /// Regularized incomplete beta function.
    fn betainc(self, a: Self, b: Self) -> Self;
    /// Inverse of incomplete beta integral.
    fn betainc_inv(self, a: Self, b: Self) -> Self;
    /// Regularized incomplete gamma integral.
    fn gammainc(self, a: Self) -> Self;
    /// Complemented incomplete gamma integral.
    fn gammac(self, a: Self) -> Self;
    /// Inverse of complemented incomplete gamma integral.
    fn gammac_inv(self, a: Self) -> Self;
    /// Normal distribution function.
    fn norm(self) -> Self;
    /// Inverse of Normal distribution function.
    fn norm_inv(self) -> Self;
    /// Bessel function of non-integer order of the first kind.
    fn besselj(self, v: Self) -> Self;
}

impl FloatSpecial for f64 {
    fn betainc(self, a: f64, b: f64) -> f64 {
        unsafe { incbet(a, b, self) }
    }
    fn betainc_inv(self, a: f64, b: f64) -> f64 {
        unsafe { incbi(a, b, self) }
    }
    fn gammainc(self, a: f64) -> f64 {
        unsafe { igam(a, self) }
    }
    fn gammac(self, a: f64) -> f64 {
        unsafe { igamc(a, self) }
    }
    fn gammac_inv(self, a: f64) -> f64 {
        unsafe { igami(a, self) }
    }
    fn norm(self) -> f64 {
        unsafe { ndtr(self) }
    }
    fn norm_inv(self) -> f64 {
        unsafe { ndtri(self) }
    }
    fn besselj(self, v: f64) -> f64 {
        unsafe { jv(v, self) }
    }
}

impl FloatSpecial for f32 {
    fn betainc(self, a: f32, b: f32) -> f32 {
        unsafe { incbetf(a, b, self) }
    }
    fn betainc_inv(self, a: f32, b: f32) -> f32 {
        unsafe { incbif(a, b, self) }
    }
    fn gammainc(self, a: f32) -> f32 {
        unsafe { igamf(a, self) }
    }
    fn gammac(self, a: f32) -> f32 {
        unsafe { igamcf(a, self) }
    }
    fn gammac_inv(self, a: f32) -> f32 {
        unsafe { igamif(a, self) }
    }
    fn norm(self) -> f32 {
        unsafe { ndtrf(self) }
    }
    fn norm_inv(self) -> f32 {
        unsafe { ndtrif(self) }
    }
    fn besselj(self, v: f32) -> f32 {
        unsafe { jvf(v, self) }
    }
}

#[cfg(test)]
mod test {
    use ::std::fmt::Debug;
    use ::num::traits::{Float, FromPrimitive};

    fn assert_almost_eq<T: Float + FromPrimitive + Debug>(a: T, b: T) {
        let tol: T = FromPrimitive::from_f32(1e-6).unwrap();
        if (a - b).abs() > tol {
            panic!("{:?} vs. {:?}", a, b);
        }
    }

    mod double {
        use super::super::FloatSpecial;
        use super::assert_almost_eq;

        #[test]
        fn beta() {
            assert_almost_eq(0.5f64.betainc(2.0, 3.0), 0.6875);
        }

        #[test]
        fn gamma() {
            assert_almost_eq(4.0f64.gammainc(2.0), 0.90842180555632912);
            assert_almost_eq(1.0 - 4.0f64.gammainc(2.0), 4.0f64.gammac(2.0));
            assert_almost_eq(4.0f64.gammac(2.0).gammac_inv(2.0), 4.0);
        }

        #[test]
        fn norm() {
            assert_almost_eq(2.0f64.norm(), 0.9772499);
            assert_almost_eq(0.9f64.norm_inv(), 1.281552);
        }

        #[test]
        fn bessel() {
            assert_almost_eq(10.0f64.besselj(2.0), 0.25463031368512062);
        }
    }

    mod single {
        use super::super::FloatSpecial;
        use super::assert_almost_eq;

        #[test]
        fn beta() {
            assert_almost_eq(0.5f32.betainc(2.0, 3.0), 0.6875);
        }

        #[test]
        fn gamma() {
            assert_almost_eq(4.0f32.gammainc(2.0), 0.90842180555632912);
            assert_almost_eq(1.0 - 4.0f32.gammainc(2.0), 4.0f32.gammac(2.0));
            assert_almost_eq(4.0f32.gammac(2.0).gammac_inv(2.0), 4.0);
        }

        #[test]
        fn norm() {
            assert_almost_eq(2.0f32.norm(), 0.9772499);
            assert_almost_eq(0.9f32.norm_inv(), 1.281552);
        }

        #[test]
        fn bessel() {
            assert_almost_eq(10.0f32.besselj(2.0), 0.25463031368512062);
        }
    }
}
<commit_msg>cephes bindings for most available functions<commit_after>extern crate num;

extern "C" {
    // Floating point numeric utilities
    /// Round to nearest or event integer valued f64.
    fn round(x: f64) -> f64;
    /// Largest integer less than or equal to x.
    fn floor(x: f64) -> f64;
    /// Smallest integer greater than or equal to x.
    fn ceil(x: f64) -> f64;
    /// Return the significand between 0.5 and 1. Write exponent to expnt.
    /// x = y * 2**expn
    fn frexp(x: f64, expnt: &mut i32) -> f64;
    /// Multiply x by 2**n.
    fn ldexp(x: f64, n: i32) -> f64;
    /// Absolute value.
    fn fabs(x: f64) -> f64;
    /// Return 1 if the sign bit of x is 1, else 0.
    fn signbit(x: f64) -> i32;
    /// Return 1 if x is NaN, else 0.
    fn isnan(x: f64) -> i32;
    /// Return 1 if x is finite, else 0.
    fn isfinite(x: f64) -> i32;

    // Roots
    /// Cube root.
    fn cbrt(x: f64) -> f64;
    /// Square root.
    fn sqrt(x: f64) -> f64;
    /// Integer square root.
    fn lsqrt(x: i64) -> i64;

    // Exponential functions
    /// Exponential function.
    fn exp(x: f64) -> f64;
    /// Base 10 exponential function.
    fn exp10(x: f64) -> f64;
    /// Base 2 exponential function.
    fn exp2(x: f64) -> f64;
    /// Exponential of squared argument.
    fn expx2(x: f64, sign: i32) -> f64;
    /// Exponential integral.
    fn ei(x: f64) -> f64;
    /// Error function.
    fn erf(x: f64) -> f64;
    /// Complementary error function.
    fn erfc(x: f64) -> f64;
    /// Power function.
    fn pow(x: f64, y: f64) -> f64;
    /// Integer power function.
    fn powi(x: f64, n: i32) -> f64;

    // Logarithmic functions
    /// Natural logarithm.
    fn log(x: f64) -> f64;
    /// Common logarithm.
    fn log10(x: f64) -> f64;
    /// Base 2 logarithm.
    fn log2(x: f64) -> f64;
    /// Dilogarithm (Spence's function).
    fn spence(x: f64) -> f64;

    // Trigonometric functions
    /// Circular sine.
    fn sin(x: f64) -> f64;
    /// Circular cosine.
    fn cos(x: f64) -> f64;
    /// Circular tangent.
    fn tan(x: f64) -> f64;
    /// Inverse circular sine.
    fn asin(x: f64) -> f64;
    /// Inverse circular cosine.
    fn acos(x: f64) -> f64;
    /// Inverse circular tangent.
    fn atan(x: f64) -> f64;
    /// Quadrant-correct inverse circular tangent.
    fn atan2(y: f64, x: f64) -> f64;
    /// Sine and cosine integrals.
    fn sici(x: f64, si: &mut f64, ci: &mut f64) -> f64;

    // Hyperbolic functions
    /// Hyperbolic sine.
    fn sinh(x: f64) -> f64;
    /// Hyperbolic cosine.
    fn cosh(x: f64) -> f64;
    /// Hyperbolic tangent.
    fn tanh(x: f64) -> f64;
    /// Inverse hyperbolic sine.
    fn asinh(x: f64) -> f64;
    /// Inverse hyperbolic cosine.
    fn acosh(x: f64) -> f64;
    /// Inverse hyperbolic tangent.
    fn atanh(x: f64) -> f64;
    /// Hyperbolic sine and cosine integrals.
    fn shichi(x: f64, chi: &mut f64, shi: &mut f64);

    // Beta functions
    /// Beta function.
    fn beta(a: f64, b: f64) -> f64;
    /// Regularized incomplete beta function.
    fn incbet(a: f64, b: f64, x: f64) -> f64;
    /// Inverse of incomplete beta integral.
    fn incbi(a: f64, b: f64, y: f64) -> f64;

    // Gamma functions
    /// Gamma function.
    fn gamma(x: f64) -> f64;
    /// Reciprocal gamma function.
    fn rgamma(x: f64) -> f64;
    /// Natural logarithm of gamma function.
    fn lgam(x: f64) -> f64;
    /// Regularized incomplete gamma integral.
    fn igam(a: f64, x: f64) -> f64;
    /// Complemented incomplete gamma integral.
    fn igamc(a: f64, x: f64) -> f64;
    /// Inverse of complemented incomplete gamma integral.
    fn igami(a: f64, p: f64) -> f64;
    /// Psi (digamma) function.
    fn psi(x: f64) -> f64;
    /// Factorial function.
    fn fac(i: i32) -> f64;

    // Bessel functions
    /// Bessel function of order zero.
    fn j0(x: f64) -> f64;
    /// Bessel function of order one.
    fn j1(x: f64) -> f64;
    /// Bessel function of integer order.
    fn jn(n: i32, x: f64) -> f64;
    /// Bessel function of noninteger order.
    fn jv(n: f64, x: f64) -> f64;

    /// Bessel function of the second kind, order zero.
    fn y0(x: f64) -> f64;
    /// Bessel function of the second kind, order one.
    fn y1(x: f64) -> f64;
    /// Bessel function of the second kind, integer order.
    fn yn(n: i32, x: f64) -> f64;

    /// Modified Bessel function of order zero.
    fn i0(x: f64) -> f64;
    /// Modified Bessel function of order zero, exponentially scaled.
    fn i0e(x: f64) -> f64;
    /// Modified Bessel function of order one.
    fn i1(x: f64) -> f64;
    /// Modified Bessel function of order one, exponentially scaled.
    fn i1e(x: f64) -> f64;
    /// Modified Bessel function of noninteger order.
    fn iv(v: f64, x: f64) -> f64;

    /// Modified Bessel function of the third kind, order zero.
    fn k0(x: f64) -> f64;
    /// Modified Bessel function of the third kind, order zero,
    /// exponentially scaled.
    fn k0e(x: f64) -> f64;
    /// Modified Bessel function of the third kind, order one.
    fn k1(x: f64) -> f64;
    /// Modified Bessel function of the third kind, order one,
    /// exponentially scaled.
    fn k1e(x: f64) -> f64;
    /// Modified Bessel function of the third kind, integer order.
    fn kn(n: i32, x: f64) -> f64;

    // Elliptic functions
    /// Incomplete elliptic integral of the first kind.
    fn ellik(phi: f64, m: f64) -> f64;
    /// Incomplete elliptic integral of the second kind.
    fn ellie(phi: f64, m: f64) -> f64;
    /// Complete elliptic integral of the first kind.
    fn ellpk(m1: f64) -> f64;
    /// Complete elliptic integral of the second kind.
    fn ellpe(m1: f64) -> f64;
    /// Jacobian elliptic function.
    fn ellpj(u: f64, m: f64, sn: &mut f64, cn: &mut f64, dn: &mut f64, phi: &mut f64) -> i32;

    // Hypergeometric functions
    /// Gauss hypergeometric function 2F1.
    fn hyp2f1(a: f64, b: f64, c: f64, x: f64) -> f64;
    /// Confluent hypergeometric function.
    fn hyperg(a: f64, b: f64, x: f64) -> f64;

    // Distributions
    /// Binomial distribution.
    fn bdtr(k: i32, n: i32, p: f64) -> f64;
    /// Complemented binomial distribution.
    fn bdtrc(k: i32, n: i32, p: f64) -> f64;
    /// Inverse of binomial distribution.
    fn bdtri(k: i32, n: i32, y: f64) -> f64;

    /// Negative binomial distribution.
    fn nbdtr(k: i32, n: i32, p: f64) -> f64;
    /// Complemented negative binomial distribution.
    fn nbdtrc(k: i32, n: i32, p: f64) -> f64;
    /// Inverse of negative binomial distribution.
    fn nbdtri(k: i32, n: i32, p: f64) -> f64;

    /// Beta distribution.
    fn btdtr(a: f64, b: f64, x: f64) -> f64;

    /// Chi-square distribution.
    fn chdtr(df: f64, x: f64) -> f64;
    /// Complemented chi-square distribution.
    fn chdtrc(v: f64, x: f64) -> f64;
    /// Inverse of complemented chi-square distribution.
    fn chdtri(df: f64, y: f64) -> f64;

    /// F distribution.
    fn fdtr(df1: i32, df2: i32, x: f64) -> f64;
    /// Complemented F distribution.
    fn fdtrc(df1: i32, df2: i32, x: f64) -> f64;
    /// Inverse of complemented F distribution.
    fn fdtri(df1: i32, df2: i32, p: f64) -> f64;

    /// Gamma distribution.
    fn gdtr(a: f64, b: f64, x: f64) -> f64;
    /// Complemented gamma distribution.
    fn gdtrc(a: f64, b: f64, x: f64) -> f64;

    /// Normal distribution.
    fn ndtr(x: f64) -> f64;
    /// Inverse of normal distribution.
    fn ndtri(y: f64) -> f64;

    /// Poisson distribution.
    fn pdtr(k: i32, m: f64) -> f64;
    /// Complemented Poisson distribution.
    fn pdtrk(k: i32, m: f64) -> f64;
    /// Inverse of Poisson distribution.
    fn pdtri(k: i32, y: f64) -> f64;

    /// Student's t distribution.
    fn stdtr(k: i16, t: f64) -> f64;
    /// Inverse of Student's t distribution.
    fn stdtri(k: i32, p: f64) -> f64;

    // Misc special functions
    /// Airy function.
    fn airy(x: f64, ai: &mut f64, aip: &mut f64, bi: &mut f64, bip: &mut f64) -> i32;
    /// Dawson's integral.
    fn dawsn(x: f64) -> f64;
    /// Fresnel integral.
    fn fresnl(x: f64, s: &mut f64, c: &mut f64);
    /// Integral of Planck's black body radiation formula.
    fn plancki(lambda: f64, temperature: f64) -> f64;
    /// Struve function.
    fn struve(v: f64, x: f64) -> f64;
    /// Riemann zeta function.
    fn zetac(x: f64) -> f64;
    /// Riemann zeta function of two arguments.
    fn zeta(x: f64, q: f64) -> f64;
}

/// Special functions on primitive floating point numbers.
/// These are essential for most statistical applications.
pub trait FloatSpecial {
    /// Regularized incomplete beta function.
    fn betainc(self, a: Self, b: Self) -> Self;
    /// Inverse of incomplete beta integral.
    fn betainc_inv(self, a: Self, b: Self) -> Self;
    /// Regularized incomplete gamma integral.
    fn gammainc(self, a: Self) -> Self;
    /// Complemented incomplete gamma integral.
    fn gammac(self, a: Self) -> Self;
    /// Inverse of complemented incomplete gamma integral.
    fn gammac_inv(self, a: Self) -> Self;
    /// Normal distribution function.
    fn norm(self) -> Self;
    /// Inverse of Normal distribution function.
    fn norm_inv(self) -> Self;
    /// Bessel function of non-integer order of the first kind.
    fn besselj(self, v: Self) -> Self;
}

impl FloatSpecial for f64 {
    fn betainc(self, a: f64, b: f64) -> f64 {
        unsafe { incbet(a, b, self) }
    }
    fn betainc_inv(self, a: f64, b: f64) -> f64 {
        unsafe { incbi(a, b, self) }
    }
    fn gammainc(self, a: f64) -> f64 {
        unsafe { igam(a, self) }
    }
    fn gammac(self, a: f64) -> f64 {
        unsafe { igamc(a, self) }
    }
    fn gammac_inv(self, a: f64) -> f64 {
        unsafe { igami(a, self) }
    }
    fn norm(self) -> f64 {
        unsafe { ndtr(self) }
    }
    fn norm_inv(self) -> f64 {
        unsafe { ndtri(self) }
    }
    fn besselj(self, v: f64) -> f64 {
        unsafe { jv(v, self) }
    }
}

/*
impl FloatSpecial for f32 {
    fn betainc(self, a: f32, b: f32) -> f32 {
        unsafe { incbetf(a, b, self) }
    }
    fn betainc_inv(self, a: f32, b: f32) -> f32 {
        unsafe { incbif(a, b, self) }
    }
    fn gammainc(self, a: f32) -> f32 {
        unsafe { igamf(a, self) }
    }
    fn gammac(self, a: f32) -> f32 {
        unsafe { igamcf(a, self) }
    }
    fn gammac_inv(self, a: f32) -> f32 {
        unsafe { igamif(a, self) }
    }
    fn norm(self) -> f32 {
        unsafe { ndtrf(self) }
    }
    fn norm_inv(self) -> f32 {
        unsafe { ndtrif(self) }
    }
    fn besselj(self, v: f32) -> f32 {
        unsafe { jvf(v, self) }
    }
}
*/

#[cfg(test)]
mod test {
    use ::std::fmt::Debug;
    use ::num::traits::{Float, FromPrimitive};

    fn assert_almost_eq<T: Float + FromPrimitive + Debug>(a: T, b: T) {
        let tol: T = FromPrimitive::from_f32(1e-6).unwrap();
        if (a - b).abs() > tol {
            panic!("{:?} vs. {:?}", a, b);
        }
    }

    mod double {
        use super::super::FloatSpecial;
        use super::assert_almost_eq;

        #[test]
        fn beta() {
            assert_almost_eq(0.5f64.betainc(2.0, 3.0), 0.6875);
        }

        #[test]
        fn gamma() {
            assert_almost_eq(4.0f64.gammainc(2.0), 0.90842180555632912);
            assert_almost_eq(1.0 - 4.0f64.gammainc(2.0), 4.0f64.gammac(2.0));
            assert_almost_eq(4.0f64.gammac(2.0).gammac_inv(2.0), 4.0);
        }

        #[test]
        fn norm() {
            assert_almost_eq(2.0f64.norm(), 0.9772499);
            assert_almost_eq(0.9f64.norm_inv(), 1.281552);
        }

        #[test]
        fn bessel() {
            assert_almost_eq(10.0f64.besselj(2.0), 0.25463031368512062);
        }
    }

    /*
    mod single {
        use super::super::FloatSpecial;
        use super::assert_almost_eq;

        #[test]
        fn beta() {
            assert_almost_eq(0.5f32.betainc(2.0, 3.0), 0.6875);
        }

        #[test]
        fn gamma() {
            assert_almost_eq(4.0f32.gammainc(2.0), 0.90842180555632912);
            assert_almost_eq(1.0 - 4.0f32.gammainc(2.0), 4.0f32.gammac(2.0));
            assert_almost_eq(4.0f32.gammac(2.0).gammac_inv(2.0), 4.0);
        }

        #[test]
        fn norm() {
            assert_almost_eq(2.0f32.norm(), 0.9772499);
            assert_almost_eq(0.9f32.norm_inv(), 1.281552);
        }

        #[test]
        fn bessel() {
            assert_almost_eq(10.0f32.besselj(2.0), 0.25463031368512062);
        }
    }
    */
}
<|endoftext|>


<commit_before>#![crate_name = "r6"]

//! r6.rs is an attempt to implement R6RS Scheme in Rust language

#![feature(plugin)]
#![feature(box_syntax)]

#![feature(slice_patterns)]
#![feature(io)]

// This line should be at the top of the extern link list,
// because some weird compiler bug lets log imported from rustc, not crates.io log
#[macro_use] extern crate log;
#[macro_use] extern crate enum_primitive;

extern crate phf;
extern crate regex;
extern crate num;
extern crate unicode_categories;
extern crate immutable_map;

macro_rules! list{
    ($($x:expr),*) => (
        vec![$($x),*].into_iter().collect()
    )
}

macro_rules! sym{
    ($e:expr) => (
        Datum::Sym(Cow::Borrowed($e))
    )
}

macro_rules! num{
    ($e:expr) => (
        Datum::Num(Number::new_int($e, 0))
    )
}

macro_rules! nil{
    () => (
        Datum::Nil
    )
}

/// Error values returned from parser, compiler or runtime
pub mod error;
/// Basic datum types
pub mod datum;
/// Implement eqv? primitive
pub mod eqv;
pub mod parser;
pub mod lexer;
/// Virtual machine running the bytecode
pub mod runtime;
/// Primitive functions
pub mod primitive;
/// Compiles datum into a bytecode
pub mod compiler;
/// R6RS `base` library
pub mod base;
/// Real part of the numerical tower
pub mod real;
/// Numerical tower
pub mod number;
/// Cast Datum into rust types
pub mod cast;
/// Macro implementations
pub mod syntax;
<commit_msg>Remove unused compiler flags<commit_after>#![crate_name = "r6"]

//! r6.rs is an attempt to implement R6RS Scheme in Rust language

#![feature(slice_patterns)]
#![feature(io)]

// This line should be at the top of the extern link list,
// because some weird compiler bug lets log imported from rustc, not crates.io log
#[macro_use] extern crate log;
#[macro_use] extern crate enum_primitive;

extern crate phf;
extern crate regex;
extern crate num;
extern crate unicode_categories;
extern crate immutable_map;

macro_rules! list{
    ($($x:expr),*) => (
        vec![$($x),*].into_iter().collect()
    )
}

macro_rules! sym{
    ($e:expr) => (
        Datum::Sym(Cow::Borrowed($e))
    )
}

macro_rules! num{
    ($e:expr) => (
        Datum::Num(Number::new_int($e, 0))
    )
}

macro_rules! nil{
    () => (
        Datum::Nil
    )
}

/// Error values returned from parser, compiler or runtime
pub mod error;
/// Basic datum types
pub mod datum;
/// Implement eqv? primitive
pub mod eqv;
pub mod parser;
pub mod lexer;
/// Virtual machine running the bytecode
pub mod runtime;
/// Primitive functions
pub mod primitive;
/// Compiles datum into a bytecode
pub mod compiler;
/// R6RS `base` library
pub mod base;
/// Real part of the numerical tower
pub mod real;
/// Numerical tower
pub mod number;
/// Cast Datum into rust types
pub mod cast;
/// Macro implementations
pub mod syntax;
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>change directory structure<commit_after>pub mod api;
<|endoftext|>