<commit_before>extern crate bindgen;

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target.contains("apple-ios") {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: Option<&str>, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        headers.push("AudioUnit/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");

        if target.contains("apple-ios") {
            headers.push("CoreAudio/CoreAudioTypes.h");
        } else {
            headers.push("CoreAudio/CoreAudio.h");
        }
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL/al.h");
        headers.push("OpenAL/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    // See https://github.com/rust-lang/rust-bindgen/issues/1211
    // Technically according to the llvm mailing list, the argument to clang here should be
    // -arch arm64 but it looks cleaner to just change the target.
    let target = if target == "aarch64-apple-ios" {
        "arm64-apple-ios"
    } else {
        target
    };

    builder = builder.clang_args(&[&format!("--target={}", target)]);

    if let Some(sdk_path) = sdk_path {
        builder = builder.clang_args(&["-isysroot", sdk_path]);
    }

    let meta_header: Vec<_> = headers
        .iter()
        .map(|h| format!("#include <{}>\n", h))
        .collect();

    builder = builder.header_contents("coreaudio.h", &meta_header.concat());

    // Generate the bindings.
    builder = builder.trust_clang_mangling(false).derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    let directory = sdk_path(&target).ok();
    build(directory.as_ref().map(String::as_ref), &target);
}
<commit_msg>Messing around with objective-c bindgen support<commit_after>extern crate bindgen;

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target.contains("apple-ios") {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: Option<&str>, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        headers.push("AudioUnit/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");

        if target.contains("apple-ios") {
            headers.push("CoreAudio/CoreAudioTypes.h");
        } else {
            headers.push("CoreAudio/CoreAudio.h");
        }
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL/al.h");
        headers.push("OpenAL/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    // See https://github.com/rust-lang/rust-bindgen/issues/1211
    // Technically according to the llvm mailing list, the argument to clang here should be
    // -arch arm64 but it looks cleaner to just change the target.
    let target = if target == "aarch64-apple-ios" {
        "arm64-apple-ios"
    } else {
        target
    };

    builder = builder.clang_args(&[&format!("--target={}", target)]);

    if let Some(sdk_path) = sdk_path {
        builder = builder.clang_args(
            &[
            "-isysroot", sdk_path,
            ]
        );
    }
    if target.contains("apple-ios") {
        builder = builder.clang_args(
            &[
            "-x", "objective-c",
            ]
        );
    }

    let meta_header: Vec<_> = headers
        .iter()
        .map(|h| format!("#include <{}>\n", h))
        .collect();

    builder = builder.header_contents("coreaudio.h", &meta_header.concat());

    // Generate the bindings.
    builder = builder.trust_clang_mangling(false).derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    let directory = sdk_path(&target).ok();
    build(directory.as_ref().map(String::as_ref), &target);
}
<|endoftext|>


<commit_before>#![feature(io)]
#![feature(path)]

use std::fs::File;
use std::io::Write;
use std::process::Command;
use std::path;
use std::env;

fn main()
{
    let dir_var = env::var("OUT_DIR").unwrap();
    let dir = path::Path::new(&dir_var).join("codegen");
    let out_file = dir.to_str().unwrap();
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file)
                       .status()
                       .unwrap();
    let output = Command::new(out_file).output().unwrap();
    if !output.status.success() {
        panic!("{}", String::from_utf8_lossy(&output.stderr[..]));
    }
    let mut f = match File::create("src/type_size.rs") {
        Ok(f) => f,
        Err(e) => panic!("{:?}", e)
    };
    f.write_all(&output.stdout[..]).unwrap();
}
<commit_msg>allow passing in libyaml cflags by envvar<commit_after>#![feature(io)]
#![feature(path)]

use std::fs::File;
use std::io::Write;
use std::process::Command;
use std::path;
use std::env;

fn main()
{
    let dir_var = env::var("OUT_DIR").unwrap();
    let compile_flags = env::var("LIBYAML_CFLAGS").unwrap_or("".to_string());
    let dir = path::Path::new(&dir_var).join("codegen");
    let out_file = dir.to_str().unwrap();
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg(&compile_flags)
                       .arg("-o")
                       .arg(out_file)
                       .status()
                       .unwrap();
    let output = Command::new(out_file).output().unwrap();
    if !output.status.success() {
        panic!("{}", String::from_utf8_lossy(&output.stderr[..]));
    }
    let mut f = match File::create("src/type_size.rs") {
        Ok(f) => f,
        Err(e) => panic!("{:?}", e)
    };
    f.write_all(&output.stdout[..]).unwrap();
}
<|endoftext|>


<commit_before>use serde;
use serde::{ Deserialize, Error };
use std::io::{ Read, Cursor };
use std;
use std::fmt::Display;
use std::convert::From;

use rtps;

pub struct CdrDeserializer<'a, R:'a> {
    data: &'a mut R
}

impl<'a, R:'a> CdrDeserializer<'a,R> {
    pub fn new(incoming: &'a mut R) -> Self {
        CdrDeserializer{ data: incoming }
    }
}

#[derive(Debug)]
pub struct CdrDeserializerError {
    thing: String
}

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

impl serde::Error for CdrDeserializerError {
    fn custom<T: Into<String>>(msg: T) -> Self {
        CdrDeserializerError{ thing: msg.into() }
    }

    fn end_of_stream() -> Self {
        unimplemented!()
    }
}

impl std::error::Error for CdrDeserializerError {
    fn description(&self) -> &str {
        ""
    }

    fn cause(&self) -> Option<&std::error::Error> {
        None
    }
}

struct CdrSeqVisitor<'a, T> where T: Sized + 'a + serde::Deserializer  {
    deserializer: &'a mut T
}

impl<'a,T> CdrSeqVisitor<'a,T> where T: serde::Deserializer {
    pub fn new(thing: &'a mut T) -> Self {
        CdrSeqVisitor{ deserializer: thing }
    }
}

impl<'a,R> serde::de::SeqVisitor for CdrSeqVisitor<'a,R> where R: serde::Deserializer {
    type Error = CdrDeserializerError;

    fn visit<T>(&mut self) -> Result<Option<T>,Self::Error> {
        let value = try!(serde::Deserialize::deserialize(self.deserializer));
        Ok(Some(value))
    }

    fn end(&mut self) -> Result<(),Self::Error> {
        panic!("sup")
    }
}

impl<'a,R> serde::Deserializer for CdrDeserializer<'a,R> {
    type Error = CdrDeserializerError;

    fn deserialize<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_bool<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_usize<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_u8<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_u16<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_u32<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_u64<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_isize<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i8<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i16<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i32<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i64<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_f32<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_f64<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_char<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_str<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_string<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_unit<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_option<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_seq<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_seq_fixed_size<V>(&mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_bytes<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_map<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_unit_struct<V>(&mut self, name: &'static str, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_newtype_struct<V>(&mut self, name: &'static str, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_tuple_struct<V>(&mut self, name: &'static str, len: usize, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_struct<V>(&mut self, name: &'static str, fields: &'static [&'static str], mut visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
//        panic!("fields: {:?}, name: {:?}", fields, name)
//        Ok()
//        if fields[0] == "junk" {
//            let junk = self.data[0];
//            try!(visitor.visit_u8(junk))
//        }
//        Err(CdrDeserializerError::custom("golly"))
        let seq_visitor = CdrSeqVisitor::new(self);
        visitor.visit_seq(seq_visitor)
    }

    fn deserialize_struct_field<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_tuple<V>(&mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_enum<V>(&mut self, name: &'static str, variants: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::EnumVisitor {
        unimplemented!()
    }

    fn deserialize_ignored_any<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }
}

#[derive(Deserialize,Debug,PartialEq)]
pub struct Message {
    junk: [u8; 4]
//    submessages: Vec<Submessage>
}

#[derive(Debug,PartialEq)]
pub struct Submessage {
//    id: rtps::SubmessageId,
//    endianness: rtps::CdrEndianness,
//    buf: rtps::common_types::ArcBuffer
}

#[test]
fn bang() {
    let mut bytes = vec![
        82, 84, 80, 83, // "RTPS"
        20, 10, // Protocol Type
        86, 19, // Vendor id
        0, 0, 0, 1, // Submessage count
        21, 1, // Submessage 0 headers
        0, 0, 0, 4, // Submessage 0 len
        1, 2, 3, 4  // Submessage 0 data
    ];

    let mut de = CdrDeserializer::new(&mut bytes);
    let message : Message = Deserialize::deserialize(&mut de).unwrap();

    assert_eq!(message, Message {
        junk: [82, 84, 80, 83]
//        submessages: vec![Submessage {
//            id: rtps::SubmessageId::DATA,
//            endianness: rtps::CdrEndianness::Little,
//            buf: rtps::common_types::ArcBuffer::from_vec(vec![])
//        }]
    });
}<commit_msg>Parses the RTPS preable<commit_after>use serde;
use serde::{ Deserialize, Error };
use std::io::{ Read, Cursor };
use std;
use std::fmt::Display;
use std::convert::From;

use rtps;

pub struct CdrDeserializer<'a, R:'a> {
    data: &'a mut R
}

impl<'a, R:'a> CdrDeserializer<'a,R> {
    pub fn new(incoming: &'a mut R) -> Self {
        CdrDeserializer{ data: incoming }
    }
}

#[derive(Debug)]
pub struct CdrDeserializerError {
    thing: String
}

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

impl serde::Error for CdrDeserializerError {
    fn custom<T: Into<String>>(msg: T) -> Self {
        CdrDeserializerError{ thing: msg.into() }
    }

    fn end_of_stream() -> Self {
        unimplemented!()
    }
}

impl std::error::Error for CdrDeserializerError {
    fn description(&self) -> &str {
        ""
    }

    fn cause(&self) -> Option<&std::error::Error> {
        None
    }
}

impl From<serde::de::value::Error> for CdrDeserializerError {
    fn from(err: serde::de::value::Error) -> CdrDeserializerError {
        CdrDeserializerError{
            thing: format!("{:?}", err)
        }
    }
}

impl From<std::io::Error> for CdrDeserializerError {
    fn from(err: std::io::Error) -> CdrDeserializerError {
        CdrDeserializerError{
            thing: format!("{:?}", err)
        }
    }
}

struct CdrSeqVisitor<'a, T> where T: Sized + 'a + serde::Deserializer  {
    deserializer: &'a mut T
}

impl<'a,T> CdrSeqVisitor<'a,T> where T: serde::Deserializer {
    pub fn new(thing: &'a mut T) -> Self {
        CdrSeqVisitor{ deserializer: thing }
    }
}

impl<'a,R> serde::de::SeqVisitor for CdrSeqVisitor<'a,R> where R: serde::Deserializer, CdrDeserializerError: std::convert::From<<R as serde::Deserializer>::Error> {
    type Error = CdrDeserializerError;

    fn visit<T>(&mut self) -> Result<Option<T>,Self::Error> where T: serde::Deserialize {
        let value = try!(serde::Deserialize::deserialize(self.deserializer));
        Ok(Some(value))
    }

    fn end(&mut self) -> Result<(),Self::Error> {
        Ok(())
    }
}

impl<'a,R: Read> serde::Deserializer for CdrDeserializer<'a,R> {
    type Error = CdrDeserializerError;

    fn deserialize<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_bool<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_usize<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_u8<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        let mut buf : [u8; 1] = [0; 1];
        try!(self.data.read(&mut buf));
        visitor.visit_u8(buf[0])
    }

    fn deserialize_u16<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_u32<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_u64<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_isize<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i8<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i16<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i32<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_i64<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_f32<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_f64<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_char<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_str<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_string<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_unit<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_option<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_seq<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_seq_fixed_size<V>(&mut self, len: usize, mut visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        let seq_visitor = CdrSeqVisitor::new(self);
        visitor.visit_seq(seq_visitor)
    }

    fn deserialize_bytes<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_map<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_unit_struct<V>(&mut self, name: &'static str, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_newtype_struct<V>(&mut self, name: &'static str, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_tuple_struct<V>(&mut self, name: &'static str, len: usize, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_struct<V>(&mut self, name: &'static str, fields: &'static [&'static str], mut visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        let seq_visitor = CdrSeqVisitor::new(self);
        visitor.visit_seq(seq_visitor)
    }

    fn deserialize_struct_field<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_tuple<V>(&mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }

    fn deserialize_enum<V>(&mut self, name: &'static str, variants: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::EnumVisitor {
        unimplemented!()
    }

    fn deserialize_ignored_any<V>(&mut self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor {
        unimplemented!()
    }
}

#[derive(Deserialize,Debug,PartialEq)]
pub struct Message {
    junk: [u8; 4]
//    submessages: Vec<Submessage>
}

#[derive(Debug,PartialEq)]
pub struct Submessage {
//    id: rtps::SubmessageId,
//    endianness: rtps::CdrEndianness,
//    buf: rtps::common_types::ArcBuffer
}

#[test]
fn bang() {
    let bytes = [
        82, 84, 80, 83, // "RTPS"
        20, 10, // Protocol Type
        86, 19, // Vendor id
        0, 0, 0, 1, // Submessage count
        21, 1, // Submessage 0 headers
        0, 0, 0, 4, // Submessage 0 len
        1, 2, 3, 4  // Submessage 0 data
    ];
    let mut cursor = Cursor::new(bytes);

    let mut de = CdrDeserializer::new(&mut cursor);
    let message : Message = Deserialize::deserialize(&mut de).unwrap();

    assert_eq!(message, Message {
        junk: [82, 84, 80, 83]
//        submessages: vec![Submessage {
//            id: rtps::SubmessageId::DATA,
//            endianness: rtps::CdrEndianness::Little,
//            buf: rtps::common_types::ArcBuffer::from_vec(vec![])
//        }]
    });
}<|endoftext|>


<commit_before>extern crate amy;

use amy::{
    Poller,
    Socket,
    Event
};

use std::net::{TcpListener, TcpStream};
use std::thread;

const IP: &'static str = "127.0.0.1:10001";

#[test]
fn register_listener_and_wait_for_connection_on_separate_threads() {
    let mut poller = Poller::<u64>::new().unwrap();
    let registrar = poller.get_registrar();
    let listener = TcpListener::bind(IP).unwrap();
    listener.set_nonblocking(true).unwrap();

    registrar.register(Socket::TcpListener(listener),
                       Event::Read,
                       5 as u64).unwrap();

    let h1 = thread::spawn(move || {
        let notifications = poller.wait(5000).unwrap();
        assert_eq!(1, notifications.len());
        assert_eq!(Event::Read, notifications[0].event);
        assert_eq!(5, notifications[0].registration.user_data);
        println!("{:?}", notifications[0]);
    });

    let h2 = thread::spawn(|| {
        TcpStream::connect(IP).unwrap();
    });

    h1.join().unwrap();
    h2.join().unwrap();
}
<commit_msg>add echo test<commit_after>extern crate amy;

use amy::{
    Poller,
    Socket,
    Event,
    Registration
};

use std::net::{TcpListener, TcpStream};
use std::thread;
use std::str;
use std::io::{Read, Write};

const IP: &'static str = "127.0.0.1:10001";

#[test]
fn echo_test() {
    let mut poller = Poller::<u64>::new().unwrap();
    let registrar = poller.get_registrar();
    let listener = TcpListener::bind(IP).unwrap();
    listener.set_nonblocking(true).unwrap();

    registrar.register(Socket::TcpListener(listener),
                       Event::Read,
                       5 as u64).unwrap();

    let msg = "Hello.\n";

    let h1 = thread::spawn(move || {
        let notifications = poller.wait(5000).unwrap();
        assert_eq!(1, notifications.len());
        assert_eq!(Event::Read, notifications[0].event);
        assert_eq!(5, notifications[0].registration.user_data);

        if let Socket::TcpListener(ref listener) = notifications[0].registration.socket {
            // Accept a connection and register the socket
            let conn = listener.accept().unwrap().0;
            conn.set_nonblocking(true).unwrap();
            let registrar = poller.get_registrar();
            registrar.register(Socket::TcpStream(conn), Event::Write, 6 as u64).unwrap();

            // Wait for the socket to become writable
            let mut notifications = poller.wait(5000).unwrap();
            assert_eq!(1, notifications.len());
            let notification = notifications.pop().unwrap();
            assert_eq!(Event::Write, notification.event);
            assert_eq!(6, notification.registration.user_data);

            // This write should work fine, since we have an empty tcp send buffer and the data is
            // small. Normally we'd need to maintain a state machine and retry until the data was
            // sent.
            let Registration {mut socket, ..} = *(notification.registration);
            if let Socket::TcpStream(ref mut sock) = socket {
                assert_eq!(msg.len(), sock.write(msg.as_bytes()).unwrap());
            } else {
                assert!(false);
            }

            // Register a read event, poll for it and perform the read
            registrar.register(socket, Event::Read, 7 as u64).unwrap();
            let mut notifications = poller.wait(5000).unwrap();
            assert_eq!(1, notifications.len());
            let mut notification = notifications.pop().unwrap();
            assert_eq!(Event::Read, notification.event);
            assert_eq!(7, notification.registration.user_data);
            let mut buf = [0; 7];
            if let Socket::TcpStream(ref mut sock) = notification.registration.socket {
                sock.read_exact(&mut buf).unwrap();
                assert_eq!(msg, str::from_utf8(&buf).unwrap());
            } else {
                assert!(false);
            }

        } else {
            assert!(false);
        }

    });

    let h2 = thread::spawn(move || {
        let mut sock = TcpStream::connect(IP).unwrap();
        let mut buf = [0; 7];
        sock.read_exact(&mut buf).unwrap();
        assert_eq!(msg, str::from_utf8(&buf).unwrap());
        sock.write_all(&buf).unwrap();
    });

    h1.join().unwrap();
    h2.join().unwrap();
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use dbus;
use dbus::Message;
use dbus::MessageItem;
use dbus::arg::IterAppend;
use dbus::tree::Access;
use dbus::tree::EmitsChangedSignal;
use dbus::tree::Factory;
use dbus::tree::MTFn;
use dbus::tree::MethodErr;
use dbus::tree::MethodInfo;
use dbus::tree::MethodResult;
use dbus::tree::PropInfo;

use uuid::Uuid;

use engine::RenameAction;

use super::types::{DbusContext, DbusErrorEnum, OPContext, TData};

use super::util::STRATIS_BASE_PATH;
use super::util::STRATIS_BASE_SERVICE;
use super::util::code_to_message_items;
use super::util::engine_to_dbus_err;
use super::util::get_next_arg;
use super::util::get_parent;
use super::util::get_uuid;
use super::util::ok_message_items;
use super::util::ref_ok_or;

pub fn create_dbus_filesystem<'a>(dbus_context: &DbusContext,
                                  parent: dbus::Path<'static>,
                                  uuid: Uuid)
                                  -> dbus::Path<'a> {
    let f = Factory::new_fn();

    let rename_method = f.method("SetName", (), rename_filesystem)
        .in_arg(("name", "s"))
        .out_arg(("action", "b"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let devnode_property = f.property::<&str, _>("Devnode", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_filesystem_devnode);

    let name_property = f.property::<&str, _>("Name", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::False)
        .on_get(get_filesystem_name);

    let pool_property = f.property::<&dbus::Path, _>("Pool", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_parent);

    let uuid_property = f.property::<&str, _>("Uuid", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_uuid);

    let object_name = format!("{}/{}",
                              STRATIS_BASE_PATH,
                              dbus_context.get_next_id().to_string());

    let interface_name = format!("{}.{}", STRATIS_BASE_SERVICE, "filesystem");

    let object_path = f.object_path(object_name, Some(OPContext::new(parent, uuid)))
        .introspectable()
        .add(f.interface(interface_name, ())
                 .add_m(rename_method)
                 .add_p(devnode_property)
                 .add_p(name_property)
                 .add_p(pool_property)
                 .add_p(uuid_property));

    let path = object_path.get_name().to_owned();
    dbus_context.actions.borrow_mut().push_add(object_path);
    path
}

fn rename_filesystem(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let new_name: &str = try!(get_next_arg(&mut iter, 0));

    let dbus_context = m.tree.get_data();
    let object_path = m.path.get_name();
    let return_message = message.method_return();
    let default_return = MessageItem::Bool(false);

    let filesystem_path = m.tree
        .get(&object_path)
        .expect("implicit argument must be in tree");
    let filesystem_data = get_data!(filesystem_path; default_return; return_message);

    let pool_path = get_parent!(m; filesystem_data; default_return; return_message);
    let pool_uuid = &get_data!(pool_path; default_return; return_message).uuid;

    let mut engine = dbus_context.engine.borrow_mut();
    let pool = get_pool!(engine; pool_uuid; default_return; return_message);

    let msg = match pool.rename_filesystem(&filesystem_data.uuid, &new_name) {
        Ok(RenameAction::NoSource) => {
            let error_message = format!("pool {} doesn't know about filesystem {}",
                                        pool_uuid,
                                        filesystem_data.uuid);
            let (rc, rs) = code_to_message_items(DbusErrorEnum::INTERNAL_ERROR, error_message);
            return_message.append3(default_return, rc, rs)
        }
        Ok(RenameAction::Identity) => {
            let (rc, rs) = ok_message_items();
            return_message.append3(default_return, rc, rs)
        }
        Ok(RenameAction::Renamed) => {
            let (rc, rs) = ok_message_items();
            return_message.append3(MessageItem::Bool(true), rc, rs)
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err(&err);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append3(default_return, rc, rs)
        }
    };

    Ok(vec![msg])
}

/// Get the devnode for an object path.
fn get_filesystem_devnode(i: &mut IterAppend,
                          p: &PropInfo<MTFn<TData>, TData>)
                          -> Result<(), MethodErr> {
    let dbus_context = p.tree.get_data();
    let object_path = p.path.get_name();

    let filesystem_path = p.tree
        .get(&object_path)
        .expect("tree must contain implicit argument");
    let filesystem_data = try!(ref_ok_or(filesystem_path.get_data(),
                                         MethodErr::failed(&format!("no data for object path {}",
                                                                    &object_path))));
    let pool_path = try!(p.tree
                             .get(&filesystem_data.parent)
                             .ok_or(MethodErr::failed(&format!("no path for parent object path {}",
                                                               &filesystem_data.parent))));
    let pool_uuid = try!(ref_ok_or(pool_path.get_data(),
                                   MethodErr::failed(&format!("no data for object path {}",
                                                              &object_path))))
            .uuid;
    let mut engine = dbus_context.engine.borrow_mut();
    let pool = try!(engine
                        .get_pool(&pool_uuid)
                        .ok_or(MethodErr::failed(&format!("no pool corresponding to uuid {}",
                                                          &pool_uuid))));
    let filesystem_uuid = &filesystem_data.uuid;
    let filesystem = try!(pool.get_filesystem(filesystem_uuid)
        .ok_or(MethodErr::failed(&format!("no name for filesystem with uuid {}",
                                          &filesystem_uuid))));
    let devnode = try!(filesystem
        .devnode()
        .map_err(|_| {
                     MethodErr::failed(&format!("no devnode for filesystem with uuid {}",
                                                &filesystem_uuid))
                 }));
    i.append(MessageItem::Str(format!("{}", devnode.display())));
    Ok(())
}

fn get_filesystem_name(i: &mut IterAppend,
                       p: &PropInfo<MTFn<TData>, TData>)
                       -> Result<(), MethodErr> {
    let dbus_context = p.tree.get_data();
    let object_path = p.path.get_name();

    let filesystem_path = p.tree
        .get(&object_path)
        .expect("tree must contain implicit argument");
    let filesystem_data = try!(ref_ok_or(filesystem_path.get_data(),
                                         MethodErr::failed(&format!("no data for object path {}",
                                                                    &object_path))));

    let pool_path = try!(p.tree
                             .get(&filesystem_data.parent)
                             .ok_or(MethodErr::failed(&format!("no path for parent object path {}",
                                                               &filesystem_data.parent))));
    let pool_uuid = try!(ref_ok_or(pool_path.get_data(),
                                   MethodErr::failed(&format!("no data for object path {}",
                                                              &object_path))))
            .uuid;

    let mut engine = dbus_context.engine.borrow_mut();
    let pool = try!(engine
                        .get_pool(&pool_uuid)
                        .ok_or(MethodErr::failed(&format!("no pool corresponding to uuid {}",
                                                          &pool_uuid))));

    let filesystem_uuid = &filesystem_data.uuid;
    i.append(try!(pool.get_filesystem(filesystem_uuid)
                      .map(|x| MessageItem::Str(x.name().to_owned()))
                      .ok_or(MethodErr::failed(&format!("no name for filesystem with uuid {}",
                                                        &filesystem_uuid)))));
    Ok(())
}
<commit_msg>Abstract the action of putting filesystem properties on the D-Bus<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use dbus;
use dbus::Message;
use dbus::MessageItem;
use dbus::arg::IterAppend;
use dbus::tree::Access;
use dbus::tree::EmitsChangedSignal;
use dbus::tree::Factory;
use dbus::tree::MTFn;
use dbus::tree::MethodErr;
use dbus::tree::MethodInfo;
use dbus::tree::MethodResult;
use dbus::tree::PropInfo;

use uuid::Uuid;

use engine::RenameAction;

use super::super::engine::Filesystem;

use super::types::{DbusContext, DbusErrorEnum, OPContext, TData};

use super::util::STRATIS_BASE_PATH;
use super::util::STRATIS_BASE_SERVICE;
use super::util::code_to_message_items;
use super::util::engine_to_dbus_err;
use super::util::get_next_arg;
use super::util::get_parent;
use super::util::get_uuid;
use super::util::ok_message_items;
use super::util::ref_ok_or;

pub fn create_dbus_filesystem<'a>(dbus_context: &DbusContext,
                                  parent: dbus::Path<'static>,
                                  uuid: Uuid)
                                  -> dbus::Path<'a> {
    let f = Factory::new_fn();

    let rename_method = f.method("SetName", (), rename_filesystem)
        .in_arg(("name", "s"))
        .out_arg(("action", "b"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let devnode_property = f.property::<&str, _>("Devnode", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_filesystem_devnode);

    let name_property = f.property::<&str, _>("Name", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::False)
        .on_get(get_filesystem_name);

    let pool_property = f.property::<&dbus::Path, _>("Pool", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_parent);

    let uuid_property = f.property::<&str, _>("Uuid", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_uuid);

    let object_name = format!("{}/{}",
                              STRATIS_BASE_PATH,
                              dbus_context.get_next_id().to_string());

    let interface_name = format!("{}.{}", STRATIS_BASE_SERVICE, "filesystem");

    let object_path = f.object_path(object_name, Some(OPContext::new(parent, uuid)))
        .introspectable()
        .add(f.interface(interface_name, ())
                 .add_m(rename_method)
                 .add_p(devnode_property)
                 .add_p(name_property)
                 .add_p(pool_property)
                 .add_p(uuid_property));

    let path = object_path.get_name().to_owned();
    dbus_context.actions.borrow_mut().push_add(object_path);
    path
}

fn rename_filesystem(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let new_name: &str = try!(get_next_arg(&mut iter, 0));

    let dbus_context = m.tree.get_data();
    let object_path = m.path.get_name();
    let return_message = message.method_return();
    let default_return = MessageItem::Bool(false);

    let filesystem_path = m.tree
        .get(&object_path)
        .expect("implicit argument must be in tree");
    let filesystem_data = get_data!(filesystem_path; default_return; return_message);

    let pool_path = get_parent!(m; filesystem_data; default_return; return_message);
    let pool_uuid = &get_data!(pool_path; default_return; return_message).uuid;

    let mut engine = dbus_context.engine.borrow_mut();
    let pool = get_pool!(engine; pool_uuid; default_return; return_message);

    let msg = match pool.rename_filesystem(&filesystem_data.uuid, &new_name) {
        Ok(RenameAction::NoSource) => {
            let error_message = format!("pool {} doesn't know about filesystem {}",
                                        pool_uuid,
                                        filesystem_data.uuid);
            let (rc, rs) = code_to_message_items(DbusErrorEnum::INTERNAL_ERROR, error_message);
            return_message.append3(default_return, rc, rs)
        }
        Ok(RenameAction::Identity) => {
            let (rc, rs) = ok_message_items();
            return_message.append3(default_return, rc, rs)
        }
        Ok(RenameAction::Renamed) => {
            let (rc, rs) = ok_message_items();
            return_message.append3(MessageItem::Bool(true), rc, rs)
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err(&err);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append3(default_return, rc, rs)
        }
    };

    Ok(vec![msg])
}

/// Get a filesystem property and place it on the D-Bus. The property is
/// found by means of the getter method which takes a reference to a
/// Filesystem and obtains the property from the filesystem.
fn get_filesystem_property<F>(i: &mut IterAppend,
                              p: &PropInfo<MTFn<TData>, TData>,
                              getter: F)
                              -> Result<(), MethodErr>
    where F: Fn(&Filesystem) -> Result<MessageItem, MethodErr>
{
    let dbus_context = p.tree.get_data();
    let object_path = p.path.get_name();

    let filesystem_path = p.tree
        .get(&object_path)
        .expect("tree must contain implicit argument");
    let filesystem_data = try!(ref_ok_or(filesystem_path.get_data(),
                                         MethodErr::failed(&format!("no data for object path {}",
                                                                    &object_path))));
    let pool_path = try!(p.tree
                             .get(&filesystem_data.parent)
                             .ok_or(MethodErr::failed(&format!("no path for parent object path {}",
                                                               &filesystem_data.parent))));
    let pool_uuid = try!(ref_ok_or(pool_path.get_data(),
                                   MethodErr::failed(&format!("no data for object path {}",
                                                              &object_path))))
            .uuid;
    let mut engine = dbus_context.engine.borrow_mut();
    let pool = try!(engine
                        .get_pool(&pool_uuid)
                        .ok_or(MethodErr::failed(&format!("no pool corresponding to uuid {}",
                                                          &pool_uuid))));
    let filesystem_uuid = &filesystem_data.uuid;
    let filesystem = try!(pool.get_filesystem(filesystem_uuid)
        .ok_or(MethodErr::failed(&format!("no name for filesystem with uuid {}",
                                          &filesystem_uuid))));
    i.append(try!(getter(filesystem)));
    Ok(())
}

/// Get the devnode for an object path.
fn get_filesystem_devnode(i: &mut IterAppend,
                          p: &PropInfo<MTFn<TData>, TData>)
                          -> Result<(), MethodErr> {

    fn get_devnode(filesystem: &Filesystem) -> Result<MessageItem, MethodErr> {
        let devnode = try!(filesystem
            .devnode()
            .map_err(|_| {
                     MethodErr::failed(&format!("no devnode for filesystem with uuid {}",
                                                filesystem.uuid()))
            }));
        Ok(MessageItem::Str(format!("{}", devnode.display())))
    }

    get_filesystem_property(i, p, get_devnode)
}

fn get_filesystem_name(i: &mut IterAppend,
                       p: &PropInfo<MTFn<TData>, TData>)
                       -> Result<(), MethodErr> {
    get_filesystem_property(i, p, |f| Ok(MessageItem::Str(f.name().to_owned())))
}
<|endoftext|>


<commit_before>extern crate lichen;

use lichen::parse::Parser;
use lichen::var::Var;
use lichen::eval::Evaluator;
use lichen::fun::MutFn;

use std::sync::{Arc,Mutex};

// Test for mutable state
#[derive(Debug)]
struct Player {
    coins: f32,
    name: String
}

#[test]
fn state_mut() {
    let src = "\n
def global\n
;\n
\n
root\n
    @global.coins 1\n
    emit \"step\"\n
    @global.coins + 5\n
    emit global.coins\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();
    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_cust_fn() {
    let src = "root\n
    @root.five (inc) 1 2 3\n
    emit root.five\n
;\n
def root\n
    five 5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let inc = MutFn::new(move |args, def| {
        let mut r = 0.;
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                r += v;
            }
        }

        return Some(Var::Num(r))
    });
    env.fun.insert("inc".to_owned(), inc);

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_def_block() {
    let src = "root\n
    emit global.name global.size\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], Var::String("my-game".to_owned()));
    assert_eq!(vars[1], Var::Num(1.5 .to_owned()));
}

#[test]
fn validate_def_block() {
    let src = "root\n
    @global.size + 0.5\n
    @global.name \"other-game\"\n
    emit global.name global.size\n\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], Var::String("other-game".to_owned()));
    assert_eq!(vars[1], Var::Num(2.0 .to_owned()));
}

#[test]
fn validate_when_block() {
    let src = "root\n
    needs_coins global.coins < 1\n
    when {needs_coins @global.coins + 2, \n
         !global.name @global.name \"new-name\"}\n
    emit global.name global.coins\n
;\n
def global\n
    coins 0\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[1], 2.0 .into());
    assert_eq!(vars[0], "new-name".into());
}

#[test]
fn save_state() {
    let src = "root\n
    emit root.coins\n
    @root.coins (inc) \"coins\" 1 2 3\n
    next:await no-where\n
    emit root.coins\n
;\n
def root\n
coins 0\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let data = Player { coins: 0.0, name: "Pan".to_owned() };
    let data = Arc::new(Mutex::new(data));

    let dc = data.clone();
    let inc = MutFn::new(move |args, def| {
        let mut r = dc.lock().unwrap();
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                r.coins += v;
            }
        }

        Some(r.coins.into())
    });
    env.fun.insert("inc".to_owned(), inc);

    let state = {
        let mut ev = Evaluator::new(&mut env);
        let (vars,_) = ev.next().unwrap();
        assert_eq!(vars[0], 0.0 .into());

        ev.save()
    };

    let state = { //save await state
        let mut ev = state.to_eval(&mut env);
        let (_,_) = ev.next().unwrap();
        ev.save()
    };

    let mut ev = state.to_eval(&mut env);
    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], 6.0 .into());

    let player = data.lock().unwrap();
    assert_eq!(player.coins, 6.0);
}

#[test]
fn validate_or_block() {
    let src = "root\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
\n
    @global.drunk true\n
\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
;\n
\n
def global\n
    drunk false
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], "not drunk".into());

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "is drunk".into());
}
<commit_msg>fix tests<commit_after>extern crate lichen;

use lichen::parse::Parser;
use lichen::var::Var;
use lichen::eval::Evaluator;
use lichen::fun::Fun;

use std::sync::{Arc,Mutex};

// Test for mutable state
#[derive(Debug)]
struct Player {
    coins: f32,
    name: String
}

#[test]
fn state_mut() {
    let src = "\n
def global\n
;\n
\n
root\n
    @global.coins 1\n
    emit \"step\"\n
    @global.coins + 5\n
    emit global.coins\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();
    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_cust_fn() {
    let src = "root\n
    @root.five (inc) 1 2 3\n
    emit root.five\n
;\n
def root\n
    five 5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let inc = Fun::new(move |args, def| {
        let mut r = 0.;
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                r += v;
            }
        }

        return Some(Var::Num(r))
    });
    env.fun.insert("inc".to_owned(), inc);

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_def_block() {
    let src = "root\n
    emit global.name global.size\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], Var::String("my-game".to_owned()));
    assert_eq!(vars[1], Var::Num(1.5 .to_owned()));
}

#[test]
fn validate_def_block() {
    let src = "root\n
    @global.size + 0.5\n
    @global.name \"other-game\"\n
    emit global.name global.size\n\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], Var::String("other-game".to_owned()));
    assert_eq!(vars[1], Var::Num(2.0 .to_owned()));
}

#[test]
fn validate_when_block() {
    let src = "root\n
    needs_coins global.coins < 1\n
    when {needs_coins @global.coins + 2, \n
         !global.name @global.name \"new-name\"}\n
    emit global.name global.coins\n
;\n
def global\n
    coins 0\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[1], 2.0 .into());
    assert_eq!(vars[0], "new-name".into());
}

#[test]
fn save_state() {
    let src = "root\n
    emit root.coins\n
    @root.coins (inc) \"coins\" 1 2 3\n
    next:await no-where\n
    emit root.coins\n
;\n
def root\n
coins 0\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let data = Player { coins: 0.0, name: "Pan".to_owned() };
    let data = Arc::new(Mutex::new(data));

    let dc = data.clone();
    let inc = Fun::new(move |args, def| {
        let mut r = dc.lock().unwrap();
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                r.coins += v;
            }
        }

        Some(r.coins.into())
    });
    env.fun.insert("inc".to_owned(), inc);

    let state = {
        let mut ev = Evaluator::new(&mut env);
        let (vars,_) = ev.next().unwrap();
        assert_eq!(vars[0], 0.0 .into());

        ev.save()
    };

    let state = { //save await state
        let mut ev = state.to_eval(&mut env);
        let (_,_) = ev.next().unwrap();
        ev.save()
    };

    let mut ev = state.to_eval(&mut env);
    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], 6.0 .into());

    let player = data.lock().unwrap();
    assert_eq!(player.coins, 6.0);
}

#[test]
fn validate_or_block() {
    let src = "root\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
\n
    @global.drunk true\n
\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
;\n
\n
def global\n
    drunk false
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], "not drunk".into());

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "is drunk".into());
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! The Gamma and derived distributions.

use self::GammaRepr::*;
use self::ChiSquaredRepr::*;

use {Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```text
/// f(x) =  x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// `shape < 1`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
#[derive(Clone, Copy, Debug)]
pub struct Gamma {
    repr: GammaRepr,
}

#[derive(Clone, Copy, Debug)]
enum GammaRepr {
    Large(GammaLargeShape),
    One(Exp),
    Small(GammaSmallShape)
}

// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.

/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaSmallShape {
    inv_shape: f64,
    large_shape: GammaLargeShape
}

/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaLargeShape {
    scale: f64,
    c: f64,
    d: f64
}

impl Gamma {
    /// Construct an object representing the `Gamma(shape, scale)`
    /// distribution.
    ///
    /// Panics if `shape <= 0` or `scale <= 0`.
    #[inline]
    pub fn new(shape: f64, scale: f64) -> Gamma {
        assert!(shape > 0.0, "Gamma::new called with shape <= 0");
        assert!(scale > 0.0, "Gamma::new called with scale <= 0");

        let repr = match shape {
            1.0         => One(Exp::new(1.0 / scale)),
            0.0 ... 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
            _           => Large(GammaLargeShape::new_raw(shape, scale))
        };
        Gamma { repr: repr }
    }
}

impl GammaSmallShape {
    fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
        GammaSmallShape {
            inv_shape: 1. / shape,
            large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
        }
    }
}

impl GammaLargeShape {
    fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
        let d = shape - 1. / 3.;
        GammaLargeShape {
            scale: scale,
            c: 1. / (9. * d).sqrt(),
            d: d
        }
    }
}

impl Sample<f64> for Gamma {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}

impl IndependentSample<f64> for Gamma {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match self.repr {
            Small(ref g) => g.ind_sample(rng),
            One(ref g) => g.ind_sample(rng),
            Large(ref g) => g.ind_sample(rng),
        }
    }
}
impl IndependentSample<f64> for GammaSmallShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let Open01(u) = rng.gen::<Open01<f64>>();

        self.large_shape.ind_sample(rng) * u.powf(self.inv_shape)
    }
}
impl IndependentSample<f64> for GammaLargeShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        loop {
            let StandardNormal(x) = rng.gen::<StandardNormal>();
            let v_cbrt = 1.0 + self.c * x;
            if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
                continue
            }

            let v = v_cbrt * v_cbrt * v_cbrt;
            let Open01(u) = rng.gen::<Open01<f64>>();

            let x_sqr = x * x;
            if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
                u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
                return self.d * v * self.scale
            }
        }
    }
}

/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
/// 2)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{ChiSquared, IndependentSample};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct ChiSquared {
    repr: ChiSquaredRepr,
}

#[derive(Clone, Copy, Debug)]
enum ChiSquaredRepr {
    // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
    // e.g. when alpha = 1/2 as it would be for this case, so special-
    // casing and using the definition of N(0,1)^2 is faster.
    DoFExactlyOne,
    DoFAnythingElse(Gamma),
}

impl ChiSquared {
    /// Create a new chi-squared distribution with degrees-of-freedom
    /// `k`. Panics if `k < 0`.
    pub fn new(k: f64) -> ChiSquared {
        let repr = if k == 1.0 {
            DoFExactlyOne
        } else {
            assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
            DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
        };
        ChiSquared { repr: repr }
    }
}
impl Sample<f64> for ChiSquared {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match self.repr {
            DoFExactlyOne => {
                // k == 1 => N(0,1)^2
                let StandardNormal(norm) = rng.gen::<StandardNormal>();
                norm * norm
            }
            DoFAnythingElse(ref g) => g.ind_sample(rng)
        }
    }
}

/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{FisherF, IndependentSample};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::thread_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct FisherF {
    numer: ChiSquared,
    denom: ChiSquared,
    // denom_dof / numer_dof so that this can just be a straight
    // multiplication, rather than a division.
    dof_ratio: f64,
}

impl FisherF {
    /// Create a new `FisherF` distribution, with the given
    /// parameter. Panics if either `m` or `n` are not positive.
    pub fn new(m: f64, n: f64) -> FisherF {
        assert!(m > 0.0, "FisherF::new called with `m < 0`");
        assert!(n > 0.0, "FisherF::new called with `n < 0`");

        FisherF {
            numer: ChiSquared::new(m),
            denom: ChiSquared::new(n),
            dof_ratio: n / m
        }
    }
}
impl Sample<f64> for FisherF {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
    }
}

/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{StudentT, IndependentSample};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct StudentT {
    chi: ChiSquared,
    dof: f64
}

impl StudentT {
    /// Create a new Student t distribution with `n` degrees of
    /// freedom. Panics if `n <= 0`.
    pub fn new(n: f64) -> StudentT {
        assert!(n > 0.0, "StudentT::new called with `n <= 0`");
        StudentT {
            chi: ChiSquared::new(n),
            dof: n
        }
    }
}
impl Sample<f64> for StudentT {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let StandardNormal(norm) = rng.gen::<StandardNormal>();
        norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
    }
}

#[cfg(test)]
mod test {
    use distributions::{Sample, IndependentSample};
    use super::{ChiSquared, StudentT, FisherF};

    #[test]
    fn test_chi_squared_one() {
        let mut chi = ChiSquared::new(1.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_small() {
        let mut chi = ChiSquared::new(0.5);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_large() {
        let mut chi = ChiSquared::new(30.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    #[should_panic]
    fn test_chi_squared_invalid_dof() {
        ChiSquared::new(-1.0);
    }

    #[test]
    fn test_f() {
        let mut f = FisherF::new(2.0, 32.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            f.sample(&mut rng);
            f.ind_sample(&mut rng);
        }
    }

    #[test]
    fn test_t() {
        let mut t = StudentT::new(11.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            t.sample(&mut rng);
            t.ind_sample(&mut rng);
        }
    }
}
<commit_msg>Don't use floating point literals in patterns.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! The Gamma and derived distributions.

use self::GammaRepr::*;
use self::ChiSquaredRepr::*;

use {Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```text
/// f(x) =  x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// `shape < 1`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
#[derive(Clone, Copy, Debug)]
pub struct Gamma {
    repr: GammaRepr,
}

#[derive(Clone, Copy, Debug)]
enum GammaRepr {
    Large(GammaLargeShape),
    One(Exp),
    Small(GammaSmallShape)
}

// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.

/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaSmallShape {
    inv_shape: f64,
    large_shape: GammaLargeShape
}

/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
#[derive(Clone, Copy, Debug)]
struct GammaLargeShape {
    scale: f64,
    c: f64,
    d: f64
}

impl Gamma {
    /// Construct an object representing the `Gamma(shape, scale)`
    /// distribution.
    ///
    /// Panics if `shape <= 0` or `scale <= 0`.
    #[inline]
    pub fn new(shape: f64, scale: f64) -> Gamma {
        assert!(shape > 0.0, "Gamma::new called with shape <= 0");
        assert!(scale > 0.0, "Gamma::new called with scale <= 0");

        let repr = if shape == 1.0 {
            One(Exp::new(1.0 / scale))
        } else if shape < 1.0 {
            Small(GammaSmallShape::new_raw(shape, scale))
        } else {
            Large(GammaLargeShape::new_raw(shape, scale))
        };
        Gamma { repr: repr }
    }
}

impl GammaSmallShape {
    fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
        GammaSmallShape {
            inv_shape: 1. / shape,
            large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
        }
    }
}

impl GammaLargeShape {
    fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
        let d = shape - 1. / 3.;
        GammaLargeShape {
            scale: scale,
            c: 1. / (9. * d).sqrt(),
            d: d
        }
    }
}

impl Sample<f64> for Gamma {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}

impl IndependentSample<f64> for Gamma {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match self.repr {
            Small(ref g) => g.ind_sample(rng),
            One(ref g) => g.ind_sample(rng),
            Large(ref g) => g.ind_sample(rng),
        }
    }
}
impl IndependentSample<f64> for GammaSmallShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let Open01(u) = rng.gen::<Open01<f64>>();

        self.large_shape.ind_sample(rng) * u.powf(self.inv_shape)
    }
}
impl IndependentSample<f64> for GammaLargeShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        loop {
            let StandardNormal(x) = rng.gen::<StandardNormal>();
            let v_cbrt = 1.0 + self.c * x;
            if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
                continue
            }

            let v = v_cbrt * v_cbrt * v_cbrt;
            let Open01(u) = rng.gen::<Open01<f64>>();

            let x_sqr = x * x;
            if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
                u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
                return self.d * v * self.scale
            }
        }
    }
}

/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
/// 2)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{ChiSquared, IndependentSample};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct ChiSquared {
    repr: ChiSquaredRepr,
}

#[derive(Clone, Copy, Debug)]
enum ChiSquaredRepr {
    // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
    // e.g. when alpha = 1/2 as it would be for this case, so special-
    // casing and using the definition of N(0,1)^2 is faster.
    DoFExactlyOne,
    DoFAnythingElse(Gamma),
}

impl ChiSquared {
    /// Create a new chi-squared distribution with degrees-of-freedom
    /// `k`. Panics if `k < 0`.
    pub fn new(k: f64) -> ChiSquared {
        let repr = if k == 1.0 {
            DoFExactlyOne
        } else {
            assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
            DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
        };
        ChiSquared { repr: repr }
    }
}
impl Sample<f64> for ChiSquared {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match self.repr {
            DoFExactlyOne => {
                // k == 1 => N(0,1)^2
                let StandardNormal(norm) = rng.gen::<StandardNormal>();
                norm * norm
            }
            DoFAnythingElse(ref g) => g.ind_sample(rng)
        }
    }
}

/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{FisherF, IndependentSample};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::thread_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct FisherF {
    numer: ChiSquared,
    denom: ChiSquared,
    // denom_dof / numer_dof so that this can just be a straight
    // multiplication, rather than a division.
    dof_ratio: f64,
}

impl FisherF {
    /// Create a new `FisherF` distribution, with the given
    /// parameter. Panics if either `m` or `n` are not positive.
    pub fn new(m: f64, n: f64) -> FisherF {
        assert!(m > 0.0, "FisherF::new called with `m < 0`");
        assert!(n > 0.0, "FisherF::new called with `n < 0`");

        FisherF {
            numer: ChiSquared::new(m),
            denom: ChiSquared::new(n),
            dof_ratio: n / m
        }
    }
}
impl Sample<f64> for FisherF {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
    }
}

/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{StudentT, IndependentSample};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::thread_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
#[derive(Clone, Copy, Debug)]
pub struct StudentT {
    chi: ChiSquared,
    dof: f64
}

impl StudentT {
    /// Create a new Student t distribution with `n` degrees of
    /// freedom. Panics if `n <= 0`.
    pub fn new(n: f64) -> StudentT {
        assert!(n > 0.0, "StudentT::new called with `n <= 0`");
        StudentT {
            chi: ChiSquared::new(n),
            dof: n
        }
    }
}
impl Sample<f64> for StudentT {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let StandardNormal(norm) = rng.gen::<StandardNormal>();
        norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
    }
}

#[cfg(test)]
mod test {
    use distributions::{Sample, IndependentSample};
    use super::{ChiSquared, StudentT, FisherF};

    #[test]
    fn test_chi_squared_one() {
        let mut chi = ChiSquared::new(1.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_small() {
        let mut chi = ChiSquared::new(0.5);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_large() {
        let mut chi = ChiSquared::new(30.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    #[should_panic]
    fn test_chi_squared_invalid_dof() {
        ChiSquared::new(-1.0);
    }

    #[test]
    fn test_f() {
        let mut f = FisherF::new(2.0, 32.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            f.sample(&mut rng);
            f.ind_sample(&mut rng);
        }
    }

    #[test]
    fn test_t() {
        let mut t = StudentT::new(11.0);
        let mut rng = ::test::rng();
        for _ in 0..1000 {
            t.sample(&mut rng);
            t.ind_sample(&mut rng);
        }
    }
}
<|endoftext|>


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

use crate::{aws::Aws, cluster::Cluster};
use failure::prelude::format_err;
use retry::{delay::Fixed, retry};
use rusoto_core::RusotoError;
use rusoto_ecr::{
    BatchGetImageRequest, DescribeImagesRequest, Ecr, Image, ImageIdentifier, PutImageError,
    PutImageRequest,
};
use rusoto_ecs::{Ecs, UpdateServiceRequest};
use slog_scope::{info, warn};
use std::{fs, io::ErrorKind, thread, time::Duration};

#[derive(Clone)]
pub struct DeploymentManager {
    aws: Aws,
    cluster: Cluster,

    last_deployed_digest: Option<String>,
}

const LAST_DEPLOYED_FILE: &str = ".last_deployed_digest";
const VALIDATOR_IMAGE_REPO: &str = "libra_e2e";
const CLIENT_IMAGE_REPO: &str = "libra_client";
const FAUCET_IMAGE_REPO: &str = "libra_faucet";
pub const SOURCE_TAG: &str = "nightly";
pub const RUNNING_TAG: &str = "cluster_test";
pub const TESTED_TAG: &str = "nightly_tested";
const UPSTREAM_PREFIX: &str = "upstream_";

impl DeploymentManager {
    pub fn new(aws: Aws, cluster: Cluster) -> Self {
        let last_deployed_digest = match fs::read_to_string(LAST_DEPLOYED_FILE) {
            Ok(v) => {
                info!("Read last deployed digest: {}", v);
                Some(v)
            }
            Err(e) => {
                if e.kind() == ErrorKind::NotFound {
                    None
                } else {
                    panic!("Failed to read .last_deployed_digest: {:?}", e);
                }
            }
        };

        Self {
            aws,
            cluster,
            last_deployed_digest,
        }
    }

    pub fn latest_hash_changed(&self) -> Option<String> {
        let hash = self.image_digest_by_tag(SOURCE_TAG);
        if let Some(last) = &self.last_deployed_digest {
            if last == &hash {
                info!("Last deployed digest matches latest digest we expect, not doing redeploy");
                return None;
            }
        } else {
            info!("Last deployed digest unknown, re-deploying anyway");
        }
        Some(hash)
    }

    pub fn redeploy(&mut self, hash: String) -> failure::Result<()> {
        info!("Will deploy with digest {}", hash);
        self.tag_image(
            VALIDATOR_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: Some(hash),
                image_tag: None,
            },
            RUNNING_TAG,
        )?;
        let _ignore = fs::remove_file(LAST_DEPLOYED_FILE);
        self.update_all_services()?;
        Ok(())
    }

    pub fn update_all_services(&self) -> failure::Result<()> {
        for instance in self.cluster.instances() {
            let mut request = UpdateServiceRequest::default();
            request.cluster = Some(self.aws.workplace().clone());
            request.force_new_deployment = Some(true);
            request.service = format!(
                "{w}/{w}-validator-{hash}",
                w = self.aws.workplace(),
                hash = instance.short_hash()
            );

            self.aws
                .ecs()
                .update_service(request)
                .sync()
                .map_err(|e| format_err!("Failed to update {}: {:?}", instance, e))?;
            thread::sleep(Duration::from_millis(100));
        }
        Ok(())
    }

    fn image_digest_by_tag(&self, tag: &str) -> String {
        let mut request = DescribeImagesRequest::default();
        request.repository_name = VALIDATOR_IMAGE_REPO.into();
        let image_id = ImageIdentifier {
            image_digest: None,
            image_tag: Some(tag.to_string()),
        };
        request.image_ids = Some(vec![image_id]);
        let result = self
            .aws
            .ecr()
            .describe_images(request)
            .sync()
            .expect("Failed to find latest nightly image");
        let images = result
            .image_details
            .expect("No image_details in ECR response");
        if images.len() != 1 {
            panic!("Ecr returned {} images for libra_e2e:nightly", images.len());
        }
        let image = images.into_iter().next().unwrap();
        image.image_digest.expect("No image_digest")
    }

    pub fn get_tested_upstream_commit(&self) -> failure::Result<String> {
        let digest = self.image_digest_by_tag(TESTED_TAG);
        let prev_upstream_tag = self.get_upstream_tag(&digest)?;
        Ok(prev_upstream_tag[UPSTREAM_PREFIX.len()..].to_string())
    }

    pub fn tag_tested_image(&mut self, hash: String) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(hash.clone()),
            image_tag: None,
        };
        self.tag_image(VALIDATOR_IMAGE_REPO, &image_id, TESTED_TAG)?;
        let upstream_tag = self.get_upstream_tag(&hash)?;
        self.tag_image(
            CLIENT_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;
        self.tag_image(
            FAUCET_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;

        fs::write(LAST_DEPLOYED_FILE, &hash).expect("Failed to write .last_deployed_digest");
        self.last_deployed_digest = Some(hash);
        let upstream_commit = upstream_tag[UPSTREAM_PREFIX.len()..].to_string();
        Ok(upstream_commit)
    }

    pub fn get_upstream_tag(&self, digest: &str) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(digest.to_string()),
            image_tag: None,
        };
        let images = self.get_images(VALIDATOR_IMAGE_REPO, &image_id)?;
        for image in images {
            let image_id = match image.image_id {
                Some(image_id) => image_id,
                None => continue,
            };
            let tag = match image_id.image_tag {
                Some(tag) => tag,
                None => continue,
            };
            if tag.starts_with(UPSTREAM_PREFIX) {
                return Ok(tag);
            }
        }
        Err(format_err!("Failed to find upstream tag"))
    }

    fn get_images(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
    ) -> failure::Result<Vec<Image>> {
        let mut get_request = BatchGetImageRequest::default();
        get_request.repository_name = repository.to_string();
        get_request.image_ids = vec![image_id.clone()];
        // Retry upto 10 times, waiting 10 sec between retries
        let response = retry(Fixed::from_millis(10_000).take(10), || {
            self.aws
                .ecr()
                .batch_get_image(get_request.clone())
                .sync()
                .map_err(|e| {
                    warn!(
                        "Failed to get image from repository: {:?}. Retrying...",
                        get_request.repository_name
                    );
                    e
                })
        })
        .map_err(|e| {
            format_err!(
                "Failed to get image from repository: {:?} after 10 tries: {:?}",
                get_request.repository_name,
                e
            )
        })?;
        response
            .images
            .ok_or_else(|| format_err!("No images in batch_get_image response"))
    }

    fn tag_image(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
        new_tag: &str,
    ) -> failure::Result<()> {
        let images = self.get_images(repository, &image_id)?;
        let image = images
            .into_iter()
            .next()
            .ok_or_else(|| format_err!("get_images returned 0 images"))?;
        let manifest = image
            .image_manifest
            .ok_or_else(|| format_err!("no manifest in batch_get_image response"))?;
        let mut put_request = PutImageRequest::default();
        put_request.image_manifest = manifest;
        put_request.repository_name = repository.to_string();
        put_request.image_tag = Some(new_tag.to_string());
        let result = self.aws.ecr().put_image(put_request).sync();
        if let Err(e) = result {
            if let RusotoError::Service(PutImageError::ImageAlreadyExists(_)) = e {
                info!("Tag for Image already exists {}:{}", repository, new_tag);
                Ok(())
            } else {
                Err(format_err!("Failed to tag image: {:?}", e))
            }
        } else {
            Ok(())
        }
    }
}
<commit_msg>[cluster-test] Do not use .last_deployed_digest file<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{aws::Aws, cluster::Cluster};
use failure::prelude::format_err;
use retry::{delay::Fixed, retry};
use rusoto_core::RusotoError;
use rusoto_ecr::{
    BatchGetImageRequest, DescribeImagesRequest, Ecr, Image, ImageIdentifier, PutImageError,
    PutImageRequest,
};
use rusoto_ecs::{Ecs, UpdateServiceRequest};
use slog_scope::{info, warn};
use std::{thread, time::Duration};

#[derive(Clone)]
pub struct DeploymentManager {
    aws: Aws,
    cluster: Cluster,
}

const VALIDATOR_IMAGE_REPO: &str = "libra_e2e";
const CLIENT_IMAGE_REPO: &str = "libra_client";
const FAUCET_IMAGE_REPO: &str = "libra_faucet";
pub const SOURCE_TAG: &str = "nightly";
pub const RUNNING_TAG: &str = "cluster_test";
pub const TESTED_TAG: &str = "nightly_tested";
const UPSTREAM_PREFIX: &str = "upstream_";

impl DeploymentManager {
    pub fn new(aws: Aws, cluster: Cluster) -> Self {
        Self { aws, cluster }
    }

    pub fn latest_hash_changed(&self) -> Option<String> {
        let hash = self.image_digest_by_tag(SOURCE_TAG);
        let last_tested = self.image_digest_by_tag(TESTED_TAG);
        if hash == last_tested {
            info!("Last deployed digest matches latest digest we expect, not doing redeploy");
            return None;
        }
        Some(hash)
    }

    pub fn redeploy(&mut self, hash: String) -> failure::Result<()> {
        info!("Will deploy with digest {}", hash);
        self.tag_image(
            VALIDATOR_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: Some(hash),
                image_tag: None,
            },
            RUNNING_TAG,
        )?;
        self.update_all_services()?;
        Ok(())
    }

    pub fn update_all_services(&self) -> failure::Result<()> {
        for instance in self.cluster.instances() {
            let mut request = UpdateServiceRequest::default();
            request.cluster = Some(self.aws.workplace().clone());
            request.force_new_deployment = Some(true);
            request.service = format!(
                "{w}/{w}-validator-{hash}",
                w = self.aws.workplace(),
                hash = instance.short_hash()
            );

            self.aws
                .ecs()
                .update_service(request)
                .sync()
                .map_err(|e| format_err!("Failed to update {}: {:?}", instance, e))?;
            thread::sleep(Duration::from_millis(100));
        }
        Ok(())
    }

    fn image_digest_by_tag(&self, tag: &str) -> String {
        let mut request = DescribeImagesRequest::default();
        request.repository_name = VALIDATOR_IMAGE_REPO.into();
        let image_id = ImageIdentifier {
            image_digest: None,
            image_tag: Some(tag.to_string()),
        };
        request.image_ids = Some(vec![image_id]);
        let result = self
            .aws
            .ecr()
            .describe_images(request)
            .sync()
            .expect("Failed to find latest nightly image");
        let images = result
            .image_details
            .expect("No image_details in ECR response");
        if images.len() != 1 {
            panic!("Ecr returned {} images for libra_e2e:nightly", images.len());
        }
        let image = images.into_iter().next().unwrap();
        image.image_digest.expect("No image_digest")
    }

    pub fn get_tested_upstream_commit(&self) -> failure::Result<String> {
        let digest = self.image_digest_by_tag(TESTED_TAG);
        let prev_upstream_tag = self.get_upstream_tag(&digest)?;
        Ok(prev_upstream_tag[UPSTREAM_PREFIX.len()..].to_string())
    }

    pub fn tag_tested_image(&mut self, hash: String) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(hash.clone()),
            image_tag: None,
        };
        self.tag_image(VALIDATOR_IMAGE_REPO, &image_id, TESTED_TAG)?;
        let upstream_tag = self.get_upstream_tag(&hash)?;
        self.tag_image(
            CLIENT_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;
        self.tag_image(
            FAUCET_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;

        let upstream_commit = upstream_tag[UPSTREAM_PREFIX.len()..].to_string();
        Ok(upstream_commit)
    }

    pub fn get_upstream_tag(&self, digest: &str) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(digest.to_string()),
            image_tag: None,
        };
        let images = self.get_images(VALIDATOR_IMAGE_REPO, &image_id)?;
        for image in images {
            let image_id = match image.image_id {
                Some(image_id) => image_id,
                None => continue,
            };
            let tag = match image_id.image_tag {
                Some(tag) => tag,
                None => continue,
            };
            if tag.starts_with(UPSTREAM_PREFIX) {
                return Ok(tag);
            }
        }
        Err(format_err!("Failed to find upstream tag"))
    }

    fn get_images(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
    ) -> failure::Result<Vec<Image>> {
        let mut get_request = BatchGetImageRequest::default();
        get_request.repository_name = repository.to_string();
        get_request.image_ids = vec![image_id.clone()];
        // Retry upto 10 times, waiting 10 sec between retries
        let response = retry(Fixed::from_millis(10_000).take(10), || {
            self.aws
                .ecr()
                .batch_get_image(get_request.clone())
                .sync()
                .map_err(|e| {
                    warn!(
                        "Failed to get image from repository: {:?}. Retrying...",
                        get_request.repository_name
                    );
                    e
                })
        })
        .map_err(|e| {
            format_err!(
                "Failed to get image from repository: {:?} after 10 tries: {:?}",
                get_request.repository_name,
                e
            )
        })?;
        response
            .images
            .ok_or_else(|| format_err!("No images in batch_get_image response"))
    }

    fn tag_image(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
        new_tag: &str,
    ) -> failure::Result<()> {
        let images = self.get_images(repository, &image_id)?;
        let image = images
            .into_iter()
            .next()
            .ok_or_else(|| format_err!("get_images returned 0 images"))?;
        let manifest = image
            .image_manifest
            .ok_or_else(|| format_err!("no manifest in batch_get_image response"))?;
        let mut put_request = PutImageRequest::default();
        put_request.image_manifest = manifest;
        put_request.repository_name = repository.to_string();
        put_request.image_tag = Some(new_tag.to_string());
        let result = self.aws.ecr().put_image(put_request).sync();
        if let Err(e) = result {
            if let RusotoError::Service(PutImageError::ImageAlreadyExists(_)) = e {
                info!("Tag for Image already exists {}:{}", repository, new_tag);
                Ok(())
            } else {
                Err(format_err!("Failed to tag image: {:?}", e))
            }
        } else {
            Ok(())
        }
    }
}
<|endoftext|>