<commit_before>use rand::distributions::{Gamma, IndependentSample};

use {Distribution, Generator};

/// A beta distribution.
pub struct Beta {
    /// The first shape parameter.
    pub alpha: f64,
    /// The second shape parameter.
    pub beta: f64,
    /// The left endpoint of the support.
    pub a: f64,
    /// The right endpoint of the support.
    pub b: f64,

    ln_beta: f64,
    gamma_alpha: Gamma,
    gamma_beta: Gamma,
}

impl Beta {
    /// Create a beta distribution with the shape parameters `alpha` and `beta`
    /// on the interval `[a, b]`.
    #[inline]
    pub fn new(alpha: f64, beta: f64, a: f64, b: f64) -> Beta {
        use special::ln_beta;
        Beta {
            alpha: alpha,
            beta: beta,
            a: a,
            b: b,
            ln_beta: ln_beta(alpha, beta),
            gamma_alpha: Gamma::new(alpha, 1.0),
            gamma_beta: Gamma::new(beta, 1.0),
        }
    }
}

impl Distribution for Beta {
    type Item = f64;

    #[inline]
    fn cdf(&self, x: f64) -> f64 {
        use special::inc_beta;
        inc_beta((x - self.a) / (self.b - self.a), self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn inv_cdf(&self, p: f64) -> f64 {
        use special::inv_inc_beta;
        self.a + (self.b - self.a) * inv_inc_beta(p, self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn sample<G: Generator>(&self, generator: &mut G) -> f64 {
        let x = self.gamma_alpha.ind_sample(generator);
        let y = self.gamma_beta.ind_sample(generator);
        self.a + (self.b - self.a) * x / (x + y)
    }
}

#[cfg(test)]
mod tests {
    use assert;

    use {Distribution, Sampler, generator};
    use distributions::Beta;

    #[test]
    fn cdf() {
        let beta = Beta::new(2.0, 3.0, -1.0, 2.0);

        let x = vec![
            -1.00, -0.85, -0.70, -0.55, -0.40, -0.25, -0.10, 0.05, 0.20, 0.35, 0.50,
             0.65,  0.80,  0.95,  1.10,  1.25,  1.40,  1.55, 1.70, 1.85, 2.00,
        ];
        let p = vec![
            0.000000000000000e+00, 1.401875000000000e-02, 5.230000000000002e-02,
            1.095187500000000e-01, 1.807999999999999e-01, 2.617187500000001e-01,
            3.483000000000000e-01, 4.370187500000001e-01, 5.248000000000003e-01,
            6.090187500000001e-01, 6.875000000000000e-01, 7.585187500000001e-01,
            8.208000000000000e-01, 8.735187499999999e-01, 9.163000000000000e-01,
            9.492187500000000e-01, 9.728000000000000e-01, 9.880187500000001e-01,
            9.963000000000000e-01, 9.995187500000000e-01, 1.000000000000000e+00,
        ];

        assert::within(&x.iter().map(|&x| beta.cdf(x)).collect::<Vec<_>>(), &p, 1e-14);
    }

    #[test]
    fn inv_cdf() {
        let beta = Beta::new(1.0, 2.0, 3.0, 4.0);

        let p = vec![
            0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50,
            0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00,
        ];
        let x = vec![
            3.000000000000000e+00, 3.025320565519104e+00, 3.051316701949486e+00,
            3.078045554270711e+00, 3.105572809000084e+00, 3.133974596215561e+00,
            3.163339973465924e+00, 3.193774225170145e+00, 3.225403330758517e+00,
            3.258380151290432e+00, 3.292893218813452e+00, 3.329179606750063e+00,
            3.367544467966324e+00, 3.408392021690038e+00, 3.452277442494834e+00,
            3.500000000000000e+00, 3.552786404500042e+00, 3.612701665379257e+00,
            3.683772233983162e+00, 3.776393202250021e+00, 4.000000000000000e+00,
        ];

        assert::within(&p.iter().map(|&p| beta.inv_cdf(p)).collect::<Vec<_>>(), &x, 1e-14);
    }

    #[test]
    fn sample() {
        for x in Sampler(&Beta::new(1.0, 2.0, 7.0, 42.0), &mut generator()).take(100) {
            assert!(7.0 <= x && x <= 42.0);
        }
    }
}

#[cfg(test)]
mod benches {
    use test;

    use {Distribution, Sampler, generator};
    use distributions::{Beta, Uniform};

    #[bench]
    fn cdf(bench: &mut test::Bencher) {
        let beta = Beta::new(0.5, 1.5, 0.0, 1.0);
        let x = Sampler(&beta, &mut generator()).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(x.iter().map(|&x| beta.cdf(x)).collect::<Vec<_>>())
        });
    }

    #[bench]
    fn inv_cdf(bench: &mut test::Bencher) {
        let beta = Beta::new(0.5, 1.5, 0.0, 1.0);
        let uniform = Uniform::new(0.0, 1.0);
        let p = Sampler(&uniform, &mut generator()).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(p.iter().map(|&p| beta.inv_cdf(p)).collect::<Vec<_>>())
        });
    }
}
<commit_msg>Derive Clone and Copy for Beta<commit_after>use rand::distributions::{Gamma, IndependentSample};

use {Distribution, Generator};

/// A beta distribution.
#[derive(Clone, Copy)]
pub struct Beta {
    /// The first shape parameter.
    pub alpha: f64,
    /// The second shape parameter.
    pub beta: f64,
    /// The left endpoint of the support.
    pub a: f64,
    /// The right endpoint of the support.
    pub b: f64,

    ln_beta: f64,
    gamma_alpha: Gamma,
    gamma_beta: Gamma,
}

impl Beta {
    /// Create a beta distribution with the shape parameters `alpha` and `beta`
    /// on the interval `[a, b]`.
    #[inline]
    pub fn new(alpha: f64, beta: f64, a: f64, b: f64) -> Beta {
        use special::ln_beta;
        Beta {
            alpha: alpha,
            beta: beta,
            a: a,
            b: b,
            ln_beta: ln_beta(alpha, beta),
            gamma_alpha: Gamma::new(alpha, 1.0),
            gamma_beta: Gamma::new(beta, 1.0),
        }
    }
}

impl Distribution for Beta {
    type Item = f64;

    #[inline]
    fn cdf(&self, x: f64) -> f64 {
        use special::inc_beta;
        inc_beta((x - self.a) / (self.b - self.a), self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn inv_cdf(&self, p: f64) -> f64 {
        use special::inv_inc_beta;
        self.a + (self.b - self.a) * inv_inc_beta(p, self.alpha, self.beta, self.ln_beta)
    }

    #[inline]
    fn sample<G: Generator>(&self, generator: &mut G) -> f64 {
        let x = self.gamma_alpha.ind_sample(generator);
        let y = self.gamma_beta.ind_sample(generator);
        self.a + (self.b - self.a) * x / (x + y)
    }
}

#[cfg(test)]
mod tests {
    use assert;

    use {Distribution, Sampler, generator};
    use distributions::Beta;

    #[test]
    fn cdf() {
        let beta = Beta::new(2.0, 3.0, -1.0, 2.0);

        let x = vec![
            -1.00, -0.85, -0.70, -0.55, -0.40, -0.25, -0.10, 0.05, 0.20, 0.35, 0.50,
             0.65,  0.80,  0.95,  1.10,  1.25,  1.40,  1.55, 1.70, 1.85, 2.00,
        ];
        let p = vec![
            0.000000000000000e+00, 1.401875000000000e-02, 5.230000000000002e-02,
            1.095187500000000e-01, 1.807999999999999e-01, 2.617187500000001e-01,
            3.483000000000000e-01, 4.370187500000001e-01, 5.248000000000003e-01,
            6.090187500000001e-01, 6.875000000000000e-01, 7.585187500000001e-01,
            8.208000000000000e-01, 8.735187499999999e-01, 9.163000000000000e-01,
            9.492187500000000e-01, 9.728000000000000e-01, 9.880187500000001e-01,
            9.963000000000000e-01, 9.995187500000000e-01, 1.000000000000000e+00,
        ];

        assert::within(&x.iter().map(|&x| beta.cdf(x)).collect::<Vec<_>>(), &p, 1e-14);
    }

    #[test]
    fn inv_cdf() {
        let beta = Beta::new(1.0, 2.0, 3.0, 4.0);

        let p = vec![
            0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50,
            0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00,
        ];
        let x = vec![
            3.000000000000000e+00, 3.025320565519104e+00, 3.051316701949486e+00,
            3.078045554270711e+00, 3.105572809000084e+00, 3.133974596215561e+00,
            3.163339973465924e+00, 3.193774225170145e+00, 3.225403330758517e+00,
            3.258380151290432e+00, 3.292893218813452e+00, 3.329179606750063e+00,
            3.367544467966324e+00, 3.408392021690038e+00, 3.452277442494834e+00,
            3.500000000000000e+00, 3.552786404500042e+00, 3.612701665379257e+00,
            3.683772233983162e+00, 3.776393202250021e+00, 4.000000000000000e+00,
        ];

        assert::within(&p.iter().map(|&p| beta.inv_cdf(p)).collect::<Vec<_>>(), &x, 1e-14);
    }

    #[test]
    fn sample() {
        for x in Sampler(&Beta::new(1.0, 2.0, 7.0, 42.0), &mut generator()).take(100) {
            assert!(7.0 <= x && x <= 42.0);
        }
    }
}

#[cfg(test)]
mod benches {
    use test;

    use {Distribution, Sampler, generator};
    use distributions::{Beta, Uniform};

    #[bench]
    fn cdf(bench: &mut test::Bencher) {
        let beta = Beta::new(0.5, 1.5, 0.0, 1.0);
        let x = Sampler(&beta, &mut generator()).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(x.iter().map(|&x| beta.cdf(x)).collect::<Vec<_>>())
        });
    }

    #[bench]
    fn inv_cdf(bench: &mut test::Bencher) {
        let beta = Beta::new(0.5, 1.5, 0.0, 1.0);
        let uniform = Uniform::new(0.0, 1.0);
        let p = Sampler(&uniform, &mut generator()).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(p.iter().map(|&p| beta.inv_cdf(p)).collect::<Vec<_>>())
        });
    }
}
<|endoftext|>


<commit_before>

use std::{env, fmt};
use std::path::PathBuf;
use error::Result;

#[derive(Clone)]
pub struct DocBuilderOptions {
    pub keep_build_directory: bool,
    pub prefix: PathBuf,
    pub destination: PathBuf,
    pub chroot_path: PathBuf,
    pub chroot_user: String,
    pub container_name: String,
    pub crates_io_index_path: PathBuf,
    pub skip_if_exists: bool,
    pub skip_if_log_exists: bool,
    pub skip_oldest_versions: bool,
    pub build_only_latest_version: bool,
    pub debug: bool,
}

impl Default for DocBuilderOptions {
    fn default() -> DocBuilderOptions {

        let cwd = env::current_dir().unwrap();

        let (prefix, destination, chroot_path, crates_io_index_path) =
            generate_paths(cwd);

        DocBuilderOptions {
            prefix: prefix,
            destination: destination,
            chroot_path: chroot_path,
            crates_io_index_path: crates_io_index_path,

            chroot_user: "cratesfyi".to_string(),
            container_name: "cratesfyi-container".to_string(),

            keep_build_directory: false,
            skip_if_exists: false,
            skip_if_log_exists: false,
            skip_oldest_versions: false,
            build_only_latest_version: false,
            debug: false,
        }
    }
}

impl fmt::Debug for DocBuilderOptions {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "DocBuilderOptions {{ destination: {:?}, chroot_path: {:?}, \
                crates_io_index_path: {:?}, \
                container_name: {:?}, chroot_user: {:?}, \
                keep_build_directory: {:?}, skip_if_exists: {:?}, \
                skip_if_log_exists: {:?}, debug: {:?} }}",
               self.destination,
               self.chroot_path,
               self.crates_io_index_path,
               self.container_name,
               self.chroot_user,
               self.keep_build_directory,
               self.skip_if_exists,
               self.skip_if_log_exists,
               self.debug)
    }
}

impl DocBuilderOptions {
    /// Creates new DocBuilderOptions from prefix
    pub fn from_prefix(prefix: PathBuf) -> DocBuilderOptions {
        let (prefix, destination, chroot_path, crates_io_index_path) =
            generate_paths(prefix);
        DocBuilderOptions {
            prefix: prefix,
            destination: destination,
            chroot_path: chroot_path,
            crates_io_index_path: crates_io_index_path,

            ..Default::default()
        }
    }

    pub fn check_paths(&self) -> Result<()> {
        if !self.destination.exists() {
            bail!("destination path '{}' does not exist", self.destination.display());
        }
        if !self.chroot_path.exists() {
            bail!("chroot path '{}' does not exist", self.chroot_path.display());
        }
        if !self.crates_io_index_path.exists() {
            bail!("crates.io-index path '{}' does not exist", self.crates_io_index_path.display());
        }
        Ok(())
    }
}

fn generate_paths(prefix: PathBuf) -> (PathBuf, PathBuf, PathBuf, PathBuf) {

    let destination = PathBuf::from(&prefix).join("documentations");
    let chroot_path = PathBuf::from(&prefix).join("cratesfyi-container/rootfs");
    let crates_io_index_path = PathBuf::from(&prefix).join("crates.io-index");

    (prefix, destination, chroot_path, crates_io_index_path)
}
<commit_msg>Make container name configurable<commit_after>

use std::{env, fmt};
use std::path::PathBuf;
use error::Result;

#[derive(Clone)]
pub struct DocBuilderOptions {
    pub keep_build_directory: bool,
    pub prefix: PathBuf,
    pub destination: PathBuf,
    pub chroot_path: PathBuf,
    pub chroot_user: String,
    pub container_name: String,
    pub crates_io_index_path: PathBuf,
    pub skip_if_exists: bool,
    pub skip_if_log_exists: bool,
    pub skip_oldest_versions: bool,
    pub build_only_latest_version: bool,
    pub debug: bool,
}

impl Default for DocBuilderOptions {
    fn default() -> DocBuilderOptions {

        let cwd = env::current_dir().unwrap();

        let (prefix, destination, chroot_path, crates_io_index_path) =
            generate_paths(cwd);

        DocBuilderOptions {
            prefix: prefix,
            destination: destination,
            chroot_path: chroot_path,
            crates_io_index_path: crates_io_index_path,

            chroot_user: "cratesfyi".to_string(),
            container_name: env::var("CRATESFYI_CONTAINER_NAME").expect("CRATESFYI_CONTAINER_NAME"),

            keep_build_directory: false,
            skip_if_exists: false,
            skip_if_log_exists: false,
            skip_oldest_versions: false,
            build_only_latest_version: false,
            debug: false,
        }
    }
}

impl fmt::Debug for DocBuilderOptions {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "DocBuilderOptions {{ destination: {:?}, chroot_path: {:?}, \
                crates_io_index_path: {:?}, \
                container_name: {:?}, chroot_user: {:?}, \
                keep_build_directory: {:?}, skip_if_exists: {:?}, \
                skip_if_log_exists: {:?}, debug: {:?} }}",
               self.destination,
               self.chroot_path,
               self.crates_io_index_path,
               self.container_name,
               self.chroot_user,
               self.keep_build_directory,
               self.skip_if_exists,
               self.skip_if_log_exists,
               self.debug)
    }
}

impl DocBuilderOptions {
    /// Creates new DocBuilderOptions from prefix
    pub fn from_prefix(prefix: PathBuf) -> DocBuilderOptions {
        let (prefix, destination, chroot_path, crates_io_index_path) =
            generate_paths(prefix);
        DocBuilderOptions {
            prefix: prefix,
            destination: destination,
            chroot_path: chroot_path,
            crates_io_index_path: crates_io_index_path,

            ..Default::default()
        }
    }

    pub fn check_paths(&self) -> Result<()> {
        if !self.destination.exists() {
            bail!("destination path '{}' does not exist", self.destination.display());
        }
        if !self.chroot_path.exists() {
            bail!("chroot path '{}' does not exist", self.chroot_path.display());
        }
        if !self.crates_io_index_path.exists() {
            bail!("crates.io-index path '{}' does not exist", self.crates_io_index_path.display());
        }
        Ok(())
    }
}

fn generate_paths(prefix: PathBuf) -> (PathBuf, PathBuf, PathBuf, PathBuf) {
    let name = env::var_os("CRATESFYI_CONTAINER_NAME").expect("CRATESFYI_CONTAINER_NAME");
    let destination = PathBuf::from(&prefix).join("documentations");
    let chroot_path = PathBuf::from(&prefix).join(&name).join("rootfs");
    let crates_io_index_path = PathBuf::from(&prefix).join("crates.io-index");

    (prefix, destination, chroot_path, crates_io_index_path)
}
<|endoftext|>


<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                      };

use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types::*;

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<ValueRef, Vec<Positional<String>>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
pub trait TranslateType {
    /// Translate `self` to an LLVM `TypeRef`
    fn translate_type(&self, context: LLVMContext) -> TypeRef;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: SymbolTable<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: SymbolTable::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }

    pub fn int_type(&self, size: usize) -> Option<TypeRef> {
        optionalise!(llvm::LLVMIntTypeInContext(self.llctx, size as c_uint))
    }

    pub fn float_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMFloatTypeInContext(self.llctx))
    }
    pub fn double_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMDoubleTypeInContext(self.llctx))
    }
    pub fn byte_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMInt8TypeInContext(self.llctx))
    }

    pub fn get_fn_decl(&self, name: &Ident) -> Option<ValueRef> {
        CString::new((&name.value).clone())
            .map(|s| optionalise!(s.as_ptr()))
            .map(|o| o.and_then(|p|
                        optionalise!(llvm::LLVMGetNamedFunction(self.llmod, p)))
                )
            .expect(&format!(
                      "Could not create C string for function name: {:?}"
                    , name
                  ))
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.get_fn_decl(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        let mut errs: Vec<Positional<String>> = vec![];
        for e in &self.equations {
            match e.pattern_length().cmp(&self.arity()) {
                Ordering::Less => errs.push(Positional {
                    pos: e.position.clone()
                  , value: format!( "[error] equation had fewer bindings \
                                     than function arity\n \
                                     [error] auto-currying is not currently \
                                     implemented.\n \
                                     signature: {}\nfunction: {}\n"
                                  , self.sig
                                  , (*e).to_sexpr(0)
                                  )
                  })
              , Ordering::Greater => errs.push(Positional {
                  pos: e.position.clone()
                , value: format!( "[error] equation bound too many arguments\n \
                                   signature: {}\nfunction: {}\n"
                                , self.sig
                                , (*e).to_sexpr(0)
                                )
              })
              , _ =>  {}
            }

        }
        if errs.is_empty() {
            unimplemented!()
        } else {
            Err(errs)
        }
    }
}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context)
          , Type::Prim(ref primitive) => primitive.translate_type(context)
          , _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self { Primitive::IntSize    => context.int_type(word_size())
                    , Primitive::UintSize   => context.int_type(word_size())
                    , Primitive::Int(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Uint(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Float      => context.float_type()
                    , Primitive::Double     => context.double_type()
                    , Primitive::Byte       => context.byte_type()
                    , _ => unimplemented!() // TODO: figure this out
                    }.expect(
                        &format!("Could not get {:?} type from LLVM", *self)
                        )
    }
}
<commit_msg>Improve compile error list code somewhat<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::ffi::CString;
use std::cmp::Ordering;
use std::mem;

use libc::c_uint;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                      , BuilderRef
                      , TypeRef
                      };

use forktable::ForkTable;
use position::Positional;
use ast::{ Node
         , Form
         , DefForm
         , Ident
         , Function };

use semantic::annotations::{ ScopedState
                           , Scoped
                           };
use semantic::types::*;

/// Result type for compiling an AST node to LLVM IR
///
/// An `IRResult` contains either a `ValueRef`, if compilation was successful,
/// or a `Positional<String>` containing an error message and the position of
/// the line of code which could not be compiled.
pub type IRResult = Result<ValueRef, Vec<Positional<String>>>;
pub type SymbolTable<'a> = ForkTable<'a, &'a str, ValueRef>;

#[inline] fn word_size() -> usize { mem::size_of::<isize>() }

/// Trait for that which may join in The Great Work
pub trait Compile {
    /// Compile `self` to an LLVM `ValueRef`
    fn to_ir(&self, context: LLVMContext) -> IRResult;
}

/// Trait for type tags that can be translated to LLVM
pub trait TranslateType {
    /// Translate `self` to an LLVM `TypeRef`
    fn translate_type(&self, context: LLVMContext) -> TypeRef;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext<'a> { pub llctx: ContextRef
                           , pub llmod: ModuleRef
                           , pub llbuilder: BuilderRef
                           , pub names: SymbolTable<'a>
                           }

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            panic!("assertion failed: {} returned null!", stringify!($target));
        } else { e }
    })
}

/// converts a raw pointer that may be null to an Option
/// the compiler will yell about this, claiming that it involves
/// an unused unsafe block, but the unsafe block is usually necessary.
macro_rules! optionalise {
    ($target:expr) => ({
            let e = unsafe { $target };
            if e.is_null() {
                None
            } else { Some(e) }
    })
}

macro_rules! try_vec {
    ($expr:expr) => ({
        if !$expr.is_empty() {
            return Err($expr)
        }
    })
}

impl<'a> LLVMContext<'a> {

    /// Constructs a new LLVM context.
    ///
    /// # Returns:
    ///   - An `LLVMContext`
    ///
    /// # Panics:
    ///   - If the LLVM C ABI returned a null value for the `Context`,
    ///     `Builder`, or `Module`
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let ctx = not_null!(llvm::LLVMContextCreate());
            LLVMContext {
                llctx: ctx
              , llmod: not_null!(llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), ctx))
              , llbuilder: not_null!(llvm::LLVMCreateBuilderInContext(ctx))
              , names: SymbolTable::new()
            }
        }
    }

    /// Dump the module's contents to stderr for debugging
    ///
    /// Apparently this is the only reasonable way to get a textual
    /// representation of a `ModuleRef` in `librustc_llvm`...
    pub fn dump(&self) {
        unsafe { llvm::LLVMDumpModule(self.llmod); }
    }

    pub fn int_type(&self, size: usize) -> Option<TypeRef> {
        optionalise!(llvm::LLVMIntTypeInContext(self.llctx, size as c_uint))
    }

    pub fn float_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMFloatTypeInContext(self.llctx))
    }
    pub fn double_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMDoubleTypeInContext(self.llctx))
    }
    pub fn byte_type(&self) -> Option<TypeRef> {
        optionalise!(llvm::LLVMInt8TypeInContext(self.llctx))
    }

    pub fn get_fn_decl(&self, name: &Ident) -> Option<ValueRef> {
        CString::new((&name.value).clone())
            .map(|s| optionalise!(s.as_ptr()))
            .map(|o| o.and_then(|p|
                        optionalise!(llvm::LLVMGetNamedFunction(self.llmod, p)))
                )
            .expect(&format!(
                      "Could not create C string for function name: {:?}"
                    , name
                  ))
    }
}

impl<'a> Drop for LLVMContext<'a> {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMDisposeBuilder(self.llbuilder);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}

impl<'a> Compile for Scoped<'a, Form<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            Form::Define(ref form) => unimplemented!()
          , Form::Let(ref form) => unimplemented!()
          , Form::If { .. } => unimplemented!()
          , Form::Call { .. } => unimplemented!()
          , Form::Lambda(ref fun) => unimplemented!()
          , Form::Logical(ref exp) => unimplemented!()
          , Form::Lit(ref c) => unimplemented!()
          , Form::NameRef(ref form) => unimplemented!()
        }
    }
}

impl<'a> Compile for Scoped<'a, DefForm<'a, ScopedState>> {
    fn to_ir(&self, context: LLVMContext) -> IRResult {
        match **self {
            DefForm::TopLevel { ref name, ref value, .. } =>
                unimplemented!()
         ,  DefForm::Function { ref name, ref fun } => {
                match context.get_fn_decl(name) {
                    Some(previous) => unimplemented!()
                  , None => unimplemented!()
                }
            }
        }
    }
}

impl<'a> Compile for Scoped<'a, Function<'a, ScopedState>> {

    fn to_ir(&self, context: LLVMContext) -> IRResult {
        let mut errs: Vec<Positional<String>> = vec![];
        // Check to see if the arities match
        for e in &self.equations {
            match e.pattern_length().cmp(&self.arity()) {
                Ordering::Less => errs.push(Positional {
                    pos: e.position.clone()
                  , value: format!( "[error] equation had fewer bindings \
                                     than function arity\n \
                                     [error] auto-currying is not currently \
                                     implemented.\n \
                                     signature: {}\nfunction: {}\n"
                                  , self.sig
                                  , (*e).to_sexpr(0)
                                  )
                  })
              , Ordering::Greater => errs.push(Positional {
                  pos: e.position.clone()
                , value: format!( "[error] equation bound too many arguments\n \
                                   signature: {}\nfunction: {}\n"
                                , self.sig
                                , (*e).to_sexpr(0)
                                )
              })
            , _ =>  {}
            }
        }
        // TODO: this could be made way more idiomatic...
        try_vec!(errs);
        unimplemented!()
    }

}

impl TranslateType for Type {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self {
            Type::Ref(ref reference)  => reference.translate_type(context)
          , Type::Prim(ref primitive) => primitive.translate_type(context)
          , _ => unimplemented!() // TODO: figure this out
        }
    }
}

impl TranslateType for Reference {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        unimplemented!() // TODO: figure this out
    }
}

impl TranslateType for Primitive {
    fn translate_type(&self, context: LLVMContext) -> TypeRef {
        match *self { Primitive::IntSize    => context.int_type(word_size())
                    , Primitive::UintSize   => context.int_type(word_size())
                    , Primitive::Int(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Uint(bits)
                        => context.int_type(bits as usize)
                    , Primitive::Float      => context.float_type()
                    , Primitive::Double     => context.double_type()
                    , Primitive::Byte       => context.byte_type()
                    , _ => unimplemented!() // TODO: figure this out
                    }.expect(
                        &format!("Could not get {:?} type from LLVM", *self)
                        )
    }
}
<|endoftext|>


<commit_before>use crate::graphics::*;

use mint;

type Vec3 = na::Vector3<f32>;

/// A struct containing all the necessary info for drawing a [`Drawable`](trait.Drawable.html).
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = nalgebra::Point2::new(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub(crate) src: Rect,
    /// The position to draw the graphic expressed as a `Point2`.
    pub(crate) dest: Point2,
    /// The orientation of the graphic in radians.
    pub(crate) rotation: f32,
    /// The x/y scale factors expressed as a `Vector2`.
    pub(crate) scale: Vector2,
    /// An offset from the center for transform operations like scale/rotation,
    /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
    /// By default these operations are done from the top-left corner, so to rotate something
    /// from the center specify `Point2::new(0.5, 0.5)` here.
    pub(crate) offset: Point2,
    /// A color to draw the target with.
    /// Default: white.
    pub(crate) color: Color,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            dest: Point2::origin(),
            rotation: 0.0,
            scale: Vector2::new(1.0, 1.0),
            offset: Point2::new(0.0, 0.0),
            color: WHITE,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        self.dest = Point2::from(p);
        self
    }

    /// Set the drawable color.  This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    /// Set the rotation of the drawable.
    pub fn rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    /// Set the scaling factors of the drawable.
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        self.scale = Vector2::from(p);
        self
    }

    /// Set the transformation offset of the drawable.
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        self.offset = Point2::from(p);
        self
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
    pub fn to_matrix(&self) -> na::Matrix4<f32> {
        let translate = Matrix4::new_translation(&Vec3::new(self.dest.x, self.dest.y, 0.0));
        let offset = Matrix4::new_translation(&Vec3::new(self.offset.x, self.offset.y, 0.0));
        let offset_inverse =
            Matrix4::new_translation(&Vec3::new(-self.offset.x, -self.offset.y, 0.0));
        let axis_angle = Vec3::z() * self.rotation;
        let rotation = Matrix4::new_rotation(axis_angle);
        let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(self.scale.x, self.scale.y, 1.0));
        translate * offset * rotation * scale * offset_inverse
    }
}

/// Create a `DrawParam` from a location.
/// Note that this takes a single-element tuple.
/// It's a little weird but keeps the trait implementations
/// from clashing.
impl<P> From<(P,)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0)
    }
}

/// Create a `DrawParam` from a location and color
impl<P> From<(P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, color): (P, Color)) -> Self {
        DrawParam::new().dest(location).color(color)
    }
}

/// Create a `DrawParam` from a location, rotation and color
impl<P> From<(P, f32, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, color): (P, f32, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset and color
impl<P> From<(P, f32, P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, offset, color): (P, f32, P, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset, scale and color
impl<P, V> From<(P, f32, P, V, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
    }
}

/// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
/// This is a lot less useful for doing transformations than I'd hoped; basically, we sometimes
/// have to modify parameters of a `DrawParam` based *on* the parameters of a `DrawParam`, for
/// instance when scaling images so that they are in units of pixels.  This makes it really
/// hard to extract scale and rotation and such, so meh.
///
/// It's still useful for a couple internal things though, so it's kept around.
#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: na::one(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        let transform = param.to_matrix();
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform.into(),
        }
    }
}

impl DrawTransform {
    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        let mat: [[f32; 4]; 4] = self.matrix.into();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<commit_msg>Make all the properties on DrawParam public<commit_after>use crate::graphics::*;

use mint;

type Vec3 = na::Vector3<f32>;

/// A struct containing all the necessary info for drawing a [`Drawable`](trait.Drawable.html).
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = nalgebra::Point2::new(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub src: Rect,
    /// The position to draw the graphic expressed as a `Point2`.
    pub dest: Point2,
    /// The orientation of the graphic in radians.
    pub rotation: f32,
    /// The x/y scale factors expressed as a `Vector2`.
    pub scale: Vector2,
    /// An offset from the center for transform operations like scale/rotation,
    /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
    /// By default these operations are done from the top-left corner, so to rotate something
    /// from the center specify `Point2::new(0.5, 0.5)` here.
    pub offset: Point2,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            dest: Point2::origin(),
            rotation: 0.0,
            scale: Vector2::new(1.0, 1.0),
            offset: Point2::new(0.0, 0.0),
            color: WHITE,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        self.dest = Point2::from(p);
        self
    }

    /// Set the drawable color.  This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    /// Set the rotation of the drawable.
    pub fn rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    /// Set the scaling factors of the drawable.
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        self.scale = Vector2::from(p);
        self
    }

    /// Set the transformation offset of the drawable.
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        self.offset = Point2::from(p);
        self
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
    pub fn to_matrix(&self) -> na::Matrix4<f32> {
        let translate = Matrix4::new_translation(&Vec3::new(self.dest.x, self.dest.y, 0.0));
        let offset = Matrix4::new_translation(&Vec3::new(self.offset.x, self.offset.y, 0.0));
        let offset_inverse =
            Matrix4::new_translation(&Vec3::new(-self.offset.x, -self.offset.y, 0.0));
        let axis_angle = Vec3::z() * self.rotation;
        let rotation = Matrix4::new_rotation(axis_angle);
        let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(self.scale.x, self.scale.y, 1.0));
        translate * offset * rotation * scale * offset_inverse
    }
}

/// Create a `DrawParam` from a location.
/// Note that this takes a single-element tuple.
/// It's a little weird but keeps the trait implementations
/// from clashing.
impl<P> From<(P,)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0)
    }
}

/// Create a `DrawParam` from a location and color
impl<P> From<(P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, color): (P, Color)) -> Self {
        DrawParam::new().dest(location).color(color)
    }
}

/// Create a `DrawParam` from a location, rotation and color
impl<P> From<(P, f32, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, color): (P, f32, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset and color
impl<P> From<(P, f32, P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, offset, color): (P, f32, P, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset, scale and color
impl<P, V> From<(P, f32, P, V, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
    }
}

/// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
/// This is a lot less useful for doing transformations than I'd hoped; basically, we sometimes
/// have to modify parameters of a `DrawParam` based *on* the parameters of a `DrawParam`, for
/// instance when scaling images so that they are in units of pixels.  This makes it really
/// hard to extract scale and rotation and such, so meh.
///
/// It's still useful for a couple internal things though, so it's kept around.
#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: na::one(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        let transform = param.to_matrix();
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform.into(),
        }
    }
}

impl DrawTransform {
    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        let mat: [[f32; 4]; 4] = self.matrix.into();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<|endoftext|>


<commit_before>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }
}

impl From<Arc<[u8]>> for SoundData {
    #[inline]
    fn from(arc: Arc<[u8]>) -> Self {
        SoundData(arc)
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let data = {
            let file = &mut context.filesystem.open(path)?;
            SoundData::from_read(file)?
        };
        Source::from_data(context, data)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        self.sink.append(decoder);
        Ok(())
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing
    pub fn playing(&self) -> bool {
        !self.paused() // && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}<commit_msg>Fix audio::playing()<commit_after>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }
}

impl From<Arc<[u8]>> for SoundData {
    #[inline]
    fn from(arc: Arc<[u8]>) -> Self {
        SoundData(arc)
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let data = {
            let file = &mut context.filesystem.open(path)?;
            SoundData::from_read(file)?
        };
        Source::from_data(context, data)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        self.sink.append(decoder);
        Ok(())
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Returns whether or not the source is stopped
    /// -- that is, has no more data to play.
    pub fn stopped(&self) {
        self.sink.empty()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing (ie, not paused
    /// and not stopped)
    pub fn playing(&self) -> bool {
        !self.paused() && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}<|endoftext|>


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

use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{from_value, Error as SerdeJsonError, Value};

use super::{
    super::{BinaryValue, UniqueHash},
    key::ProofListKey,
    HashTag,
};
use exonum_crypto::Hash;

#[derive(Debug, PartialEq, Eq)]
/// Encapsulates a proof of absence for `ProofListIndex`.
///
/// Proof of absence for an element with the specified index consists of
/// `merkle_root` of `ProofListIndex` and `length` of the list.
///
/// Element with `index` is absent in the list with provided `length`
/// and `merkle_root` when two conditions are met:
/// ```text
/// 1. list_hash == sha256( HashTag::List || length || merkle_root )
/// 2. index > length
/// ```
///
/// In case of a range proof this rule applies to the whole range.
pub struct ProofOfAbsence {
    length: u64,
    merkle_root: Hash,
}

impl ProofOfAbsence {
    /// New `ProofOfAbsence` for specified list `length` and `merkle_root`.
    pub fn new(length: u64, merkle_root: Hash) -> Self {
        Self {
            length,
            merkle_root,
        }
    }

    pub fn length(&self) -> u64 {
        self.length
    }

    pub fn merkle_root(&self) -> Hash {
        self.merkle_root
    }
}

/// An enum that represents a proof of existence for proof list elements.
#[derive(Debug, PartialEq, Eq)]
pub enum ListProof<V> {
    /// A branch of proof in which both children contain requested elements.
    Full(Box<ListProof<V>>, Box<ListProof<V>>),
    /// A branch of proof in which only the left child contains requested elements.
    Left(Box<ListProof<V>>, Option<Hash>),
    /// A branch of proof in which only the right child contains requested elements.
    Right(Hash, Box<ListProof<V>>),
    /// A leaf of the proof with the requested element.
    Leaf(V),
    /// Proof of absence of an element with the specified index.
    Absent(ProofOfAbsence),
}

/// An error that is returned when the list proof is invalid.
#[derive(Debug)]
pub enum ListProofError {
    /// The proof is too short and does not correspond to the height of the tree.
    UnexpectedLeaf,
    /// The proof is too long and does not correspond to the height of the tree.
    UnexpectedBranch,
    /// The hash of the proof is not equal to the trusted root hash.
    UnmatchedRootHash,
}

impl<V> ListProof<V>
where
    V: BinaryValue + UniqueHash,
{
    fn collect<'a>(
        &'a self,
        key: ProofListKey,
        vec: &mut Vec<(u64, &'a V)>,
    ) -> Result<Hash, ListProofError> {
        if key.height() == 0 {
            return Err(ListProofError::UnexpectedBranch);
        }
        let hash = match *self {
            ListProof::Full(ref left, ref right) => HashTag::hash_node(
                &left.collect(key.left(), vec)?,
                &right.collect(key.right(), vec)?,
            ),
            ListProof::Left(ref left, Some(ref right)) => {
                HashTag::hash_node(&left.collect(key.left(), vec)?, right)
            }
            ListProof::Left(ref left, None) => {
                HashTag::hash_single_node(&left.collect(key.left(), vec)?)
            }
            ListProof::Right(ref left, ref right) => {
                HashTag::hash_node(left, &right.collect(key.right(), vec)?)
            }
            ListProof::Leaf(ref value) => {
                if key.height() > 1 {
                    return Err(ListProofError::UnexpectedLeaf);
                }
                vec.push((key.index(), value));
                HashTag::hash_leaf(&value.to_bytes())
            }
            ListProof::Absent(ref proof) => {
                HashTag::hash_list_node(proof.length, proof.merkle_root)
            }
        };
        Ok(hash)
    }

    /// Verifies the correctness of the proof by the trusted list hash and the number of
    /// elements in the tree.
    ///
    /// To validate the proof one needs to provide `expected_list_hash` calculated as follows:
    /// ```text
    /// h = sha-256( HashTag::List || len as u64 || merkle_root )
    /// ```
    /// and `length` of the `ProofListIndex`.
    ///
    /// If the proof is valid, a vector with indices and references to elements is returned.
    /// Otherwise, `Err` is returned.
    ///
    /// If the proof is the proof of absence, then empty vector will be returned.
    pub fn validate(
        &self,
        expected_list_hash: Hash,
        len: u64,
    ) -> Result<Vec<(u64, &V)>, ListProofError> {
        let mut vec = Vec::new();
        let height = len.next_power_of_two().trailing_zeros() as u8 + 1;
        let root_hash = self.collect(ProofListKey::new(height, 0), &mut vec)?;

        match *self {
            ListProof::Absent(ref _proof) => {
                if expected_list_hash != root_hash {
                    return Err(ListProofError::UnmatchedRootHash);
                }
            }
            _ => {
                if HashTag::hash_list_node(len, root_hash) != expected_list_hash {
                    return Err(ListProofError::UnmatchedRootHash);
                }
            }
        }
        Ok(vec)
    }
}

impl<V: Serialize> Serialize for ListProof<V> {
    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        use self::ListProof::*;
        let mut state;
        match *self {
            Full(ref left_proof, ref right_proof) => {
                state = ser.serialize_struct("Full", 2)?;
                state.serialize_field("left", left_proof)?;
                state.serialize_field("right", right_proof)?;
            }
            Left(ref left_proof, ref option_hash) => {
                if let Some(ref hash) = *option_hash {
                    state = ser.serialize_struct("Left", 2)?;
                    state.serialize_field("left", left_proof)?;
                    state.serialize_field("right", &hash)?;
                } else {
                    state = ser.serialize_struct("Left", 1)?;
                    state.serialize_field("left", left_proof)?;
                }
            }
            Right(ref hash, ref right_proof) => {
                state = ser.serialize_struct("Right", 2)?;
                state.serialize_field("left", &hash)?;
                state.serialize_field("right", right_proof)?;
            }
            Leaf(ref val) => {
                state = ser.serialize_struct("Leaf", 1)?;
                state.serialize_field("val", val)?;
            }
            ListProof::Absent(ref proof) => {
                state = ser.serialize_struct("Absent", 2)?;
                state.serialize_field("length", &proof.length)?;
                state.serialize_field("hash", &proof.merkle_root)?;
            }
        }
        state.end()
    }
}
impl<'a, V> Deserialize<'a> for ListProof<V>
where
    for<'de> V: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'a>,
    {
        fn format_err_string(type_str: &str, value: &Value, err: &SerdeJsonError) -> String {
            format!(
                "Couldn't deserialize {} from serde_json::Value: {}, error: {}",
                type_str, value, err
            )
        }

        let json: Value = <Value as Deserialize>::deserialize(deserializer)?;
        if !json.is_object() {
            return Err(D::Error::custom(format!(
                "Invalid json: it is expected to be json \
                 Object. json: {:?}",
                json
            )));
        }
        let map_key_value = json.as_object().unwrap();
        let res: Self = match map_key_value.len() {
            2 => {
                let left_value: &Value = match map_key_value.get("left") {
                    None => {
                        return Err(D::Error::custom(format!(
                            "Invalid json: Key {} not found. \
                             Value: {:?}",
                            "left", json
                        )))
                    }
                    Some(left) => left,
                };
                let right_value: &Value = match map_key_value.get("right") {
                    None => {
                        return Err(D::Error::custom(format!(
                            "Invalid json: Key {} not found. \
                             Value: {:?}",
                            "right", json
                        )))
                    }
                    Some(right) => right,
                };
                if right_value.is_string() {
                    let left_proof: Self = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", left_value, &err))
                    })?;
                    let right_hash: Hash = from_value(right_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("Hash", right_value, &err))
                    })?;
                    ListProof::Left(Box::new(left_proof), Some(right_hash))
                } else if left_value.is_string() {
                    let right_proof: Self = from_value(right_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", right_value, &err))
                    })?;
                    let left_hash: Hash = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("Hash", left_value, &err))
                    })?;
                    ListProof::Right(left_hash, Box::new(right_proof))
                } else {
                    let left_proof = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", left_value, &err))
                    })?;
                    let right_proof = from_value(right_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", right_value, &err))
                    })?;
                    ListProof::Full(Box::new(left_proof), Box::new(right_proof))
                }
            }
            1 => {
                if map_key_value.get("val").is_none() && map_key_value.get("left").is_none() {
                    return Err(D::Error::custom(format!(
                        "Invalid json: unknown key met. \
                         Expected: {} or {}. json: {:?}",
                        "val", "left", json
                    )));
                }
                if let Some(leaf_value) = map_key_value.get("val") {
                    let val: V = from_value(leaf_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("V", leaf_value, &err))
                    })?;
                    ListProof::Leaf(val)
                } else {
                    // "left" is present
                    let left_value = map_key_value.get("left").unwrap();
                    let left_proof: Self = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", left_value, &err))
                    })?;
                    ListProof::Left(Box::new(left_proof), None)
                }
            }
            _ => {
                return Err(D::Error::custom(format!(
                    "Invalid json: Number of keys should be \
                     either 1 or 2. json: {:?}",
                    json
                )))
            }
        };
        Ok(res)
    }
}
<commit_msg>Update src/proof_list_index/proof.rs<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{from_value, Error as SerdeJsonError, Value};

use super::{
    super::{BinaryValue, UniqueHash},
    key::ProofListKey,
    HashTag,
};
use exonum_crypto::Hash;

#[derive(Debug, PartialEq, Eq)]
/// Encapsulates a proof of absence for `ProofListIndex`.
///
/// Proof of absence for an element with the specified index consists of
/// `merkle_root` of `ProofListIndex` and `length` of the list.
///
/// Element with `index` is absent in the list with provided `length`
/// and `merkle_root` when two conditions are met:
/// ```text
/// 1. list_hash == sha256( HashTag::List || length || merkle_root )
/// 2. index > length
/// ```
///
/// In case of a range proof this rule applies to the whole range.
pub struct ProofOfAbsence {
    length: u64,
    merkle_root: Hash,
}

impl ProofOfAbsence {
    /// New `ProofOfAbsence` for specified list `length` and `merkle_root`.
    pub fn new(length: u64, merkle_root: Hash) -> Self {
        Self {
            length,
            merkle_root,
        }
    }

    pub fn length(&self) -> u64 {
        self.length
    }

    pub fn merkle_root(&self) -> Hash {
        self.merkle_root
    }
}

/// An enum that represents a proof of existence for proof list elements.
#[derive(Debug, PartialEq, Eq)]
pub enum ListProof<V> {
    /// A branch of proof in which both children contain requested elements.
    Full(Box<ListProof<V>>, Box<ListProof<V>>),
    /// A branch of proof in which only the left child contains requested elements.
    Left(Box<ListProof<V>>, Option<Hash>),
    /// A branch of proof in which only the right child contains requested elements.
    Right(Hash, Box<ListProof<V>>),
    /// A leaf of the proof with the requested element.
    Leaf(V),
    /// Proof of absence of an element with the specified index.
    Absent(ProofOfAbsence),
}

/// An error that is returned when the list proof is invalid.
#[derive(Debug)]
pub enum ListProofError {
    /// The proof is too short and does not correspond to the height of the tree.
    UnexpectedLeaf,
    /// The proof is too long and does not correspond to the height of the tree.
    UnexpectedBranch,
    /// The hash of the proof is not equal to the trusted root hash.
    UnmatchedRootHash,
}

impl<V> ListProof<V>
where
    V: BinaryValue + UniqueHash,
{
    fn collect<'a>(
        &'a self,
        key: ProofListKey,
        vec: &mut Vec<(u64, &'a V)>,
    ) -> Result<Hash, ListProofError> {
        if key.height() == 0 {
            return Err(ListProofError::UnexpectedBranch);
        }
        let hash = match *self {
            ListProof::Full(ref left, ref right) => HashTag::hash_node(
                &left.collect(key.left(), vec)?,
                &right.collect(key.right(), vec)?,
            ),
            ListProof::Left(ref left, Some(ref right)) => {
                HashTag::hash_node(&left.collect(key.left(), vec)?, right)
            }
            ListProof::Left(ref left, None) => {
                HashTag::hash_single_node(&left.collect(key.left(), vec)?)
            }
            ListProof::Right(ref left, ref right) => {
                HashTag::hash_node(left, &right.collect(key.right(), vec)?)
            }
            ListProof::Leaf(ref value) => {
                if key.height() > 1 {
                    return Err(ListProofError::UnexpectedLeaf);
                }
                vec.push((key.index(), value));
                HashTag::hash_leaf(&value.to_bytes())
            }
            ListProof::Absent(ref proof) => {
                HashTag::hash_list_node(proof.length, proof.merkle_root)
            }
        };
        Ok(hash)
    }

    /// Verifies the correctness of the proof by the trusted list hash and the number of
    /// elements in the tree.
    ///
    /// To validate the proof one needs to provide `expected_list_hash` calculated as follows:
    /// ```text
    /// h = sha-256( HashTag::List || len as u64 || merkle_root )
    /// ```
    /// and `length` of the `ProofListIndex`.
    ///
    /// If the proof is valid, a vector with indices and references to elements is returned.
    /// Otherwise, `Err` is returned.
    ///
    /// If the proof is the proof of absence, then empty vector will be returned.
    pub fn validate(
        &self,
        expected_list_hash: Hash,
        len: u64,
    ) -> Result<Vec<(u64, &V)>, ListProofError> {
        let mut vec = Vec::new();
        let height = len.next_power_of_two().trailing_zeros() as u8 + 1;
        let root_hash = self.collect(ProofListKey::new(height, 0), &mut vec)?;

        match *self {
            ListProof::Absent(_) => {
                if expected_list_hash != root_hash {
                    return Err(ListProofError::UnmatchedRootHash);
                }
            }
            _ => {
                if HashTag::hash_list_node(len, root_hash) != expected_list_hash {
                    return Err(ListProofError::UnmatchedRootHash);
                }
            }
        }
        Ok(vec)
    }
}

impl<V: Serialize> Serialize for ListProof<V> {
    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        use self::ListProof::*;
        let mut state;
        match *self {
            Full(ref left_proof, ref right_proof) => {
                state = ser.serialize_struct("Full", 2)?;
                state.serialize_field("left", left_proof)?;
                state.serialize_field("right", right_proof)?;
            }
            Left(ref left_proof, ref option_hash) => {
                if let Some(ref hash) = *option_hash {
                    state = ser.serialize_struct("Left", 2)?;
                    state.serialize_field("left", left_proof)?;
                    state.serialize_field("right", &hash)?;
                } else {
                    state = ser.serialize_struct("Left", 1)?;
                    state.serialize_field("left", left_proof)?;
                }
            }
            Right(ref hash, ref right_proof) => {
                state = ser.serialize_struct("Right", 2)?;
                state.serialize_field("left", &hash)?;
                state.serialize_field("right", right_proof)?;
            }
            Leaf(ref val) => {
                state = ser.serialize_struct("Leaf", 1)?;
                state.serialize_field("val", val)?;
            }
            ListProof::Absent(ref proof) => {
                state = ser.serialize_struct("Absent", 2)?;
                state.serialize_field("length", &proof.length)?;
                state.serialize_field("hash", &proof.merkle_root)?;
            }
        }
        state.end()
    }
}
impl<'a, V> Deserialize<'a> for ListProof<V>
where
    for<'de> V: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'a>,
    {
        fn format_err_string(type_str: &str, value: &Value, err: &SerdeJsonError) -> String {
            format!(
                "Couldn't deserialize {} from serde_json::Value: {}, error: {}",
                type_str, value, err
            )
        }

        let json: Value = <Value as Deserialize>::deserialize(deserializer)?;
        if !json.is_object() {
            return Err(D::Error::custom(format!(
                "Invalid json: it is expected to be json \
                 Object. json: {:?}",
                json
            )));
        }
        let map_key_value = json.as_object().unwrap();
        let res: Self = match map_key_value.len() {
            2 => {
                let left_value: &Value = match map_key_value.get("left") {
                    None => {
                        return Err(D::Error::custom(format!(
                            "Invalid json: Key {} not found. \
                             Value: {:?}",
                            "left", json
                        )))
                    }
                    Some(left) => left,
                };
                let right_value: &Value = match map_key_value.get("right") {
                    None => {
                        return Err(D::Error::custom(format!(
                            "Invalid json: Key {} not found. \
                             Value: {:?}",
                            "right", json
                        )))
                    }
                    Some(right) => right,
                };
                if right_value.is_string() {
                    let left_proof: Self = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", left_value, &err))
                    })?;
                    let right_hash: Hash = from_value(right_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("Hash", right_value, &err))
                    })?;
                    ListProof::Left(Box::new(left_proof), Some(right_hash))
                } else if left_value.is_string() {
                    let right_proof: Self = from_value(right_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", right_value, &err))
                    })?;
                    let left_hash: Hash = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("Hash", left_value, &err))
                    })?;
                    ListProof::Right(left_hash, Box::new(right_proof))
                } else {
                    let left_proof = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", left_value, &err))
                    })?;
                    let right_proof = from_value(right_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", right_value, &err))
                    })?;
                    ListProof::Full(Box::new(left_proof), Box::new(right_proof))
                }
            }
            1 => {
                if map_key_value.get("val").is_none() && map_key_value.get("left").is_none() {
                    return Err(D::Error::custom(format!(
                        "Invalid json: unknown key met. \
                         Expected: {} or {}. json: {:?}",
                        "val", "left", json
                    )));
                }
                if let Some(leaf_value) = map_key_value.get("val") {
                    let val: V = from_value(leaf_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("V", leaf_value, &err))
                    })?;
                    ListProof::Leaf(val)
                } else {
                    // "left" is present
                    let left_value = map_key_value.get("left").unwrap();
                    let left_proof: Self = from_value(left_value.clone()).map_err(|err| {
                        D::Error::custom(format_err_string("ListProof", left_value, &err))
                    })?;
                    ListProof::Left(Box::new(left_proof), None)
                }
            }
            _ => {
                return Err(D::Error::custom(format!(
                    "Invalid json: Number of keys should be \
                     either 1 or 2. json: {:?}",
                    json
                )))
            }
        };
        Ok(res)
    }
}
<|endoftext|>