<commit_before>use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::Command;

use cargo::util::{self, CargoResult, ChainError, Config, Filesystem};
use chrono::NaiveDate;
use curl::http;
use flate2::read::GzDecoder;
use rustc_version::{self, Channel};
use tar::Archive;
use tempdir::TempDir;
use term::color::GREEN;

use Target;

/// Create a sysroot that looks like this:
///
/// ``` text
/// ~/.xargo
/// ├── date
/// ├── lib
/// │   └── rustlib
/// │       ├── $HOST
/// │       │   └── lib
/// │       │       ├── libcore-$hash.rlib -> $SYSROOT/lib/rustlib/$HOST/lib/libcore-$hash.rlib
/// │       │       └── (..)
/// │       ├── $TARGET1
/// │       │   ├── hash
/// │       │   └── lib
/// │       │       ├── libcore-$hash.rlib
/// │       │       └── (..)
/// │       ├── $TARGET2
/// │       │   └── (..)
/// │       ├── (..)
/// │       └── $TARGETN
/// │           └── (..)
/// └── src
///     │── libcore
///     │── libstd
///     └── (..)
/// ```
///
/// Where:
///
/// - `$SYSROOT` is the current `rustc` sysroot i.e. `$(rustc --print sysroot)`
/// - `$HOST` is the current `rustc`'s host i.e. the host field in `$(rustc -Vv)`
/// - `$TARGET*` are the custom targets `xargo` is managing
///
/// The `~/.xargo` is mostly a "standard" sysroot but with extra information:
///
/// - the `hash` files which track changes in the `$TARGET`s' specification files (i.e.
/// `$TARGET.json`).
/// - the `src` directory which holds the source code of the current `rustc` (and standard crates).
/// - the `date` file which holds the build date of the current `rustc`.
pub fn create(config: &Config, target: &Target, root: &Filesystem) -> CargoResult<()> {
    let meta = rustc_version::version_meta_for(&config.rustc_info().verbose_version);

    if meta.channel != Channel::Nightly {
        return Err(util::human("Only the nightly channel is currently supported"));
    }

    let commit_date = try!(meta.commit_date
                               .as_ref()
                               .and_then(|s| NaiveDate::parse_from_str(s, "%Y-%m-%d").ok())
                               .ok_or(util::human("couldn't find/parse the commit date from \
                                                   `rustc -Vv`")));
    // XXX AFAIK this is not guaranteed to be correct, but it appears to be a good approximation.
    let build_date = commit_date.succ();

    try!(update_source(config, &build_date, root));
    try!(rebuild_sysroot(config, root, target));
    try!(symlink_host_crates(config, root));

    Ok(())
}

fn update_source(config: &Config, date: &NaiveDate, root: &Filesystem) -> CargoResult<()> {
    const TARBALL: &'static str = "rustc-nightly-src.tar.gz";

    /// Reads the `NaiveDate` stored in `~/.xargo/date`
    fn read_date(mut file: &File) -> CargoResult<Option<NaiveDate>> {
        let date = &mut String::new();
        try!(file.read_to_string(date));

        Ok(NaiveDate::parse_from_str(date, "%Y-%m-%d").ok())
    }

    fn download(config: &Config, date: &NaiveDate) -> CargoResult<http::Response> {
        const B_PER_S: usize = 1;
        const MS: usize = 1_000;
        const S: usize = 1;

        // NOTE Got these settings from cargo (src/cargo/ops/registry.rs)
        let mut handle = http::handle()
                             .timeout(0)
                             .connect_timeout(30 * MS)
                             .low_speed_limit(10 * B_PER_S)
                             .low_speed_timeout(30 * S);;

        let url = format!("https://static.rust-lang.org/dist/{}/{}",
                          date.format("%Y-%m-%d"),
                          TARBALL);

        try!(config.shell().out().say_status("Downloading", &url, GREEN, true));
        let resp = try!(handle.get(url).follow_redirects(true).exec());

        let code = resp.get_code();
        if code != 200 {
            return Err(util::human(format!("HTTP error got {}, expected 200", code)));
        }

        Ok(resp)
    }

    fn unpack(config: &Config, tarball: http::Response, root: &Path) -> CargoResult<()> {
        try!(config.shell().out().say_status("Unpacking", TARBALL, GREEN, true));

        let src_dir = &root.join("src");
        try!(fs::create_dir(src_dir));

        let decoder = try!(GzDecoder::new(tarball.get_body()));
        let mut archive = Archive::new(decoder);
        for entry in try!(archive.entries()) {
            let mut entry = try!(entry);
            let path = {
                let path = try!(entry.path());
                let mut components = path.components();
                components.next();
                let next = components.next().and_then(|s| s.as_os_str().to_str());
                if next != Some("src") {
                    continue;
                }
                components.as_path().to_path_buf()
            };
            try!(entry.unpack(src_dir.join(path)));
        }

        Ok(())
    }

    let lock = try!(root.open_rw("date", config, "xargo"));

    if try!(read_date(lock.file())).as_ref() == Some(date) {
        // Source is up to date
        return Ok(());
    }

    try!(lock.remove_siblings());
    let tarball = try!(download(config, date)
                           .chain_error(|| util::human("Couldn't fetch Rust source tarball")));
    try!(unpack(config, tarball, lock.parent())
             .chain_error(|| util::human("Couldn't unpack Rust source tarball")));

    let mut file = lock.file();
    try!(file.set_len(0));
    try!(file.write_all(date.format("%Y-%m-%d").to_string().as_bytes()));

    Ok(())
}

fn rebuild_sysroot(config: &Config, root: &Filesystem, target: &Target) -> CargoResult<()> {
    /// Reads the hash stored in `~/.xargo/lib/rustlib/$TARGET/hash`
    fn read_hash(mut file: &File) -> CargoResult<Option<u64>> {
        let hash = &mut String::new();
        try!(file.read_to_string(hash));
        Ok(hash.parse().ok())
    }

    const CRATES: &'static [&'static str] = &["collections", "rand"];
    const TOML: &'static str = "[package]
name = 'sysroot'
version = '0.0.0'

[dependencies]
";

    let outer_lock = try!(root.open_ro("date", config, "xargo"));
    let lock = try!(root.open_rw(format!("lib/rustlib/{}/hash", target.triple),
                                 config,
                                 &format!("xargo/{}", target.triple)));
    let root = outer_lock.parent();

    if try!(read_hash(lock.file())) == Some(target.hash) {
        // Target specification file unchanged
        return Ok(());
    }

    let target_dir = lock.parent();
    try!(config.shell().out().say_status("Compiling",
                                         format!("sysroot for {}", target.triple),
                                         GREEN,
                                         true));

    let td = try!(TempDir::new("xargo"));
    let td = td.path();

    // Create Cargo project
    try!(fs::create_dir(td.join("src")));
    try!(fs::copy(&target.path, td.join(target.path.file_name().unwrap())));
    try!(File::create(td.join("src/lib.rs")));
    let toml = &mut String::from(TOML);
    for krate in CRATES {
        toml.push_str(&format!("{} = {{ path = '{}' }}\n",
                               krate,
                               root.join(format!("src/lib{}", krate)).display()))
    }
    try!(try!(File::create(td.join("Cargo.toml"))).write_all(toml.as_bytes()));

    // Build Cargo project
    let cargo = &mut Command::new("cargo");
    cargo.args(&["build", "--release", "--target"]);
    cargo.arg(&target.triple);
    for krate in CRATES {
        cargo.args(&["-p", krate]);
    }
    cargo.current_dir(td);
    let status = try!(cargo.status());

    if !status.success() {
        return Err(util::human("`cargo` process didn't exit successfully"));
    }

    // Copy build artifacts
    if target_dir.exists() {
        try!(fs::remove_dir_all(target_dir));
    }
    let dst = &target_dir.join("lib");
    try!(fs::create_dir_all(dst));
    for entry in try!(fs::read_dir(td.join(format!("target/{}/release/deps", target.triple)))) {
        let src = &try!(entry).path();
        try!(fs::copy(src, dst.join(src.file_name().unwrap())));
    }

    let mut file = lock.file();
    try!(file.set_len(0));
    try!(file.write_all(target.hash.to_string().as_bytes()));

    Ok(())
}

fn symlink_host_crates(config: &Config, root: &Filesystem) -> CargoResult<()> {
    let _outer_lock = try!(root.open_ro("date", config, "xargo"));
    let host = &config.rustc_info().host;
    let lock = try!(root.open_rw(format!("lib/rustlib/{}/sentinel", host), config, &format!("xargo/{}", host)));
    let dst = &lock.parent().join("lib");

    if dst.exists() {
        return Ok(());
    }

    try!(fs::create_dir_all(dst));
    let src = try!(sysroot()).join(format!("lib/rustlib/{}/lib", host));

    for entry in try!(fs::read_dir(src)) {
        let src = &try!(entry).path();

        try!(fs::hard_link(src, dst.join(src.file_name().unwrap())));
    }

    Ok(())
}

fn sysroot() -> CargoResult<PathBuf> {
    let mut sysroot = try!(String::from_utf8(try!(Command::new("rustc")
                                                      .args(&["--print", "sysroot"])
                                                      .output())
                                                 .stdout)
                               .map_err(|_| {
                                   util::human("output of `rustc --print sysroot` is not UTF-8")
                               }));

    while sysroot.ends_with('\n') {
        sysroot.pop();
    }

    Ok(PathBuf::from(sysroot))
}
<commit_msg>don't rm -rf the directory that contains the lock file<commit_after>use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::Command;

use cargo::util::{self, CargoResult, ChainError, Config, Filesystem};
use chrono::NaiveDate;
use curl::http;
use flate2::read::GzDecoder;
use rustc_version::{self, Channel};
use tar::Archive;
use tempdir::TempDir;
use term::color::GREEN;

use Target;

/// Create a sysroot that looks like this:
///
/// ``` text
/// ~/.xargo
/// ├── date
/// ├── lib
/// │   └── rustlib
/// │       ├── $HOST
/// │       │   └── lib
/// │       │       ├── libcore-$hash.rlib -> $SYSROOT/lib/rustlib/$HOST/lib/libcore-$hash.rlib
/// │       │       └── (..)
/// │       ├── $TARGET1
/// │       │   ├── hash
/// │       │   └── lib
/// │       │       ├── libcore-$hash.rlib
/// │       │       └── (..)
/// │       ├── $TARGET2
/// │       │   └── (..)
/// │       ├── (..)
/// │       └── $TARGETN
/// │           └── (..)
/// └── src
///     │── libcore
///     │── libstd
///     └── (..)
/// ```
///
/// Where:
///
/// - `$SYSROOT` is the current `rustc` sysroot i.e. `$(rustc --print sysroot)`
/// - `$HOST` is the current `rustc`'s host i.e. the host field in `$(rustc -Vv)`
/// - `$TARGET*` are the custom targets `xargo` is managing
///
/// The `~/.xargo` is mostly a "standard" sysroot but with extra information:
///
/// - the `hash` files which track changes in the `$TARGET`s' specification files (i.e.
/// `$TARGET.json`).
/// - the `src` directory which holds the source code of the current `rustc` (and standard crates).
/// - the `date` file which holds the build date of the current `rustc`.
pub fn create(config: &Config, target: &Target, root: &Filesystem) -> CargoResult<()> {
    let meta = rustc_version::version_meta_for(&config.rustc_info().verbose_version);

    if meta.channel != Channel::Nightly {
        return Err(util::human("Only the nightly channel is currently supported"));
    }

    let commit_date = try!(meta.commit_date
                               .as_ref()
                               .and_then(|s| NaiveDate::parse_from_str(s, "%Y-%m-%d").ok())
                               .ok_or(util::human("couldn't find/parse the commit date from \
                                                   `rustc -Vv`")));
    // XXX AFAIK this is not guaranteed to be correct, but it appears to be a good approximation.
    let build_date = commit_date.succ();

    try!(update_source(config, &build_date, root));
    try!(rebuild_sysroot(config, root, target));
    try!(symlink_host_crates(config, root));

    Ok(())
}

fn update_source(config: &Config, date: &NaiveDate, root: &Filesystem) -> CargoResult<()> {
    const TARBALL: &'static str = "rustc-nightly-src.tar.gz";

    /// Reads the `NaiveDate` stored in `~/.xargo/date`
    fn read_date(mut file: &File) -> CargoResult<Option<NaiveDate>> {
        let date = &mut String::new();
        try!(file.read_to_string(date));

        Ok(NaiveDate::parse_from_str(date, "%Y-%m-%d").ok())
    }

    fn download(config: &Config, date: &NaiveDate) -> CargoResult<http::Response> {
        const B_PER_S: usize = 1;
        const MS: usize = 1_000;
        const S: usize = 1;

        // NOTE Got these settings from cargo (src/cargo/ops/registry.rs)
        let mut handle = http::handle()
                             .timeout(0)
                             .connect_timeout(30 * MS)
                             .low_speed_limit(10 * B_PER_S)
                             .low_speed_timeout(30 * S);;

        let url = format!("https://static.rust-lang.org/dist/{}/{}",
                          date.format("%Y-%m-%d"),
                          TARBALL);

        try!(config.shell().out().say_status("Downloading", &url, GREEN, true));
        let resp = try!(handle.get(url).follow_redirects(true).exec());

        let code = resp.get_code();
        if code != 200 {
            return Err(util::human(format!("HTTP error got {}, expected 200", code)));
        }

        Ok(resp)
    }

    fn unpack(config: &Config, tarball: http::Response, root: &Path) -> CargoResult<()> {
        try!(config.shell().out().say_status("Unpacking", TARBALL, GREEN, true));

        let src_dir = &root.join("src");
        try!(fs::create_dir(src_dir));

        let decoder = try!(GzDecoder::new(tarball.get_body()));
        let mut archive = Archive::new(decoder);
        for entry in try!(archive.entries()) {
            let mut entry = try!(entry);
            let path = {
                let path = try!(entry.path());
                let mut components = path.components();
                components.next();
                let next = components.next().and_then(|s| s.as_os_str().to_str());
                if next != Some("src") {
                    continue;
                }
                components.as_path().to_path_buf()
            };
            try!(entry.unpack(src_dir.join(path)));
        }

        Ok(())
    }

    let lock = try!(root.open_rw("date", config, "xargo"));

    if try!(read_date(lock.file())).as_ref() == Some(date) {
        // Source is up to date
        return Ok(());
    }

    try!(lock.remove_siblings());
    let tarball = try!(download(config, date)
                           .chain_error(|| util::human("Couldn't fetch Rust source tarball")));
    try!(unpack(config, tarball, lock.parent())
             .chain_error(|| util::human("Couldn't unpack Rust source tarball")));

    let mut file = lock.file();
    try!(file.set_len(0));
    try!(file.write_all(date.format("%Y-%m-%d").to_string().as_bytes()));

    Ok(())
}

fn rebuild_sysroot(config: &Config, root: &Filesystem, target: &Target) -> CargoResult<()> {
    /// Reads the hash stored in `~/.xargo/lib/rustlib/$TARGET/hash`
    fn read_hash(mut file: &File) -> CargoResult<Option<u64>> {
        let hash = &mut String::new();
        try!(file.read_to_string(hash));
        Ok(hash.parse().ok())
    }

    const CRATES: &'static [&'static str] = &["collections", "rand"];
    const TOML: &'static str = "[package]
name = 'sysroot'
version = '0.0.0'

[dependencies]
";

    let outer_lock = try!(root.open_ro("date", config, "xargo"));
    let lock = try!(root.open_rw(format!("lib/rustlib/{}/hash", target.triple),
                                 config,
                                 &format!("xargo/{}", target.triple)));
    let root = outer_lock.parent();

    if try!(read_hash(lock.file())) == Some(target.hash) {
        // Target specification file unchanged
        return Ok(());
    }

    let lib_dir = &lock.parent().join("lib");
    try!(config.shell().out().say_status("Compiling",
                                         format!("sysroot for {}", target.triple),
                                         GREEN,
                                         true));

    let td = try!(TempDir::new("xargo"));
    let td = td.path();

    // Create Cargo project
    try!(fs::create_dir(td.join("src")));
    try!(fs::copy(&target.path, td.join(target.path.file_name().unwrap())));
    try!(File::create(td.join("src/lib.rs")));
    let toml = &mut String::from(TOML);
    for krate in CRATES {
        toml.push_str(&format!("{} = {{ path = '{}' }}\n",
                               krate,
                               root.join(format!("src/lib{}", krate)).display()))
    }
    try!(try!(File::create(td.join("Cargo.toml"))).write_all(toml.as_bytes()));

    // Build Cargo project
    let cargo = &mut Command::new("cargo");
    cargo.args(&["build", "--release", "--target"]);
    cargo.arg(&target.triple);
    for krate in CRATES {
        cargo.args(&["-p", krate]);
    }
    cargo.current_dir(td);
    let status = try!(cargo.status());

    if !status.success() {
        return Err(util::human("`cargo` process didn't exit successfully"));
    }

    // Copy build artifacts
    if lib_dir.exists() {
        try!(fs::remove_dir_all(lib_dir));
    }
    let dst = lib_dir;
    try!(fs::create_dir_all(dst));
    for entry in try!(fs::read_dir(td.join(format!("target/{}/release/deps", target.triple)))) {
        let src = &try!(entry).path();
        try!(fs::copy(src, dst.join(src.file_name().unwrap())));
    }

    let mut file = lock.file();
    try!(file.set_len(0));
    try!(file.write_all(target.hash.to_string().as_bytes()));

    Ok(())
}

fn symlink_host_crates(config: &Config, root: &Filesystem) -> CargoResult<()> {
    let _outer_lock = try!(root.open_ro("date", config, "xargo"));
    let host = &config.rustc_info().host;
    let lock = try!(root.open_rw(format!("lib/rustlib/{}/sentinel", host), config, &format!("xargo/{}", host)));
    let dst = &lock.parent().join("lib");

    if dst.exists() {
        return Ok(());
    }

    try!(fs::create_dir_all(dst));
    let src = try!(sysroot()).join(format!("lib/rustlib/{}/lib", host));

    for entry in try!(fs::read_dir(src)) {
        let src = &try!(entry).path();

        try!(fs::hard_link(src, dst.join(src.file_name().unwrap())));
    }

    Ok(())
}

fn sysroot() -> CargoResult<PathBuf> {
    let mut sysroot = try!(String::from_utf8(try!(Command::new("rustc")
                                                      .args(&["--print", "sysroot"])
                                                      .output())
                                                 .stdout)
                               .map_err(|_| {
                                   util::human("output of `rustc --print sysroot` is not UTF-8")
                               }));

    while sysroot.ends_with('\n') {
        sysroot.pop();
    }

    Ok(PathBuf::from(sysroot))
}
<|endoftext|>


<commit_before>use std::path::Path;
use { gfx, ImageSize, Settings };
use image::{
    self,
    DynamicImage,
    GenericImage,
    RgbaImage,
};

/// Represents a texture.
#[derive(Clone, Debug)]
pub struct Texture<R: gfx::Resources> {
    /// A handle to the Gfx texture.
    pub handle: gfx::TextureHandle<R>,
}

impl<R: gfx::Resources> Texture<R> {
    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        settings: &Settings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        //if settings.force_alpha //TODO
        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba(),
        };

        let img = if settings.flip_vertical {
            image::imageops::flip_vertical(&img)
        } else {
            img
        };

        let texture = Texture::from_image(factory, &img,
                                          settings.convert_gamma,
                                          settings.compress,
                                          settings.generate_mipmap);
        Ok(texture)
    }

    /// Creates a texture from image.
    pub fn from_image<F: gfx::Factory<R>>(
        factory: &mut F,
        image: &RgbaImage,
        convert_gamma: bool,
        _compress: bool,
        generate_mipmap: bool
    ) -> Self {
        let (width, height) = image.dimensions();
        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: if convert_gamma {
                gfx::tex::Format::SRGB8_A8
            }else { gfx::tex::RGBA8 },
        };
        let image_info = texture_info.to_image_info();
        let texture = factory.create_texture(texture_info).unwrap();
        factory.update_texture(&texture, &image_info, &image,
                               Some(gfx::tex::TextureKind::Texture2D)).unwrap();
        if generate_mipmap {
            factory.generate_mipmap(&texture);
        }
        Texture {
            handle: texture
        }
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F: gfx::Factory<R>>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
    ) -> Self {
        use std::cmp::max;

        let width = max(width, 1);
        let height = max(height, 1);

        let mut pixels = Vec::new();
        for alpha in buffer.iter() {
            pixels.push(255);
            pixels.push(255);
            pixels.push(255);
            pixels.push(*alpha);
        }

        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: gfx::tex::RGBA8,
        };

        let image_info = texture_info.to_image_info();
        let texture = factory.create_texture(texture_info).unwrap();
        factory.update_texture(&texture, &image_info, &pixels,
                               Some(gfx::tex::TextureKind::Texture2D)).unwrap();
        Texture {
            handle: texture
        }
    }

    /// Updates the texture with an image.
    pub fn update<F: gfx::Factory<R>>(&mut self, factory: &mut F, image: &RgbaImage) {
        factory.update_texture(&self.handle,
            &self.handle.get_info().to_image_info(),
            &image,
            Some(gfx::tex::TextureKind::Texture2D)
        ).unwrap();
    }
}

impl<R: gfx::Resources> ImageSize for Texture<R> {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let info = self.handle.get_info();
        (info.width as u32, info.height as u32)
    }
}
<commit_msg>Add handle method<commit_after>use std::path::Path;
use { gfx, ImageSize, Settings };
use image::{
    self,
    DynamicImage,
    GenericImage,
    RgbaImage,
};

/// Represents a texture.
#[derive(Clone, Debug, PartialEq)]
pub struct Texture<R> where R: gfx::Resources {
    handle: gfx::TextureHandle<R>
}

impl<R: gfx::Resources> Texture<R> {
    /// Get a handle to the Gfx texture.
    pub fn handle(&self) -> gfx::TextureHandle<R> {
        self.handle.clone()
    }

    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        settings: &Settings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        //if settings.force_alpha //TODO
        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba(),
        };

        let img = if settings.flip_vertical {
            image::imageops::flip_vertical(&img)
        } else {
            img
        };

        let texture = Texture::from_image(factory, &img,
                                          settings.convert_gamma,
                                          settings.compress,
                                          settings.generate_mipmap);
        Ok(texture)
    }

    /// Creates a texture from image.
    pub fn from_image<F>(
        factory: &mut F,
        image: &RgbaImage,
        convert_gamma: bool,
        _compress: bool,
        generate_mipmap: bool
    ) -> Self
        where F: gfx::Factory<R>
    {
        let (width, height) = image.dimensions();
        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: if convert_gamma {
                gfx::tex::Format::SRGB8_A8
            } else { gfx::tex::RGBA8 }
        };
        let image_info = texture_info.to_image_info();
        let texture = factory.create_texture(texture_info).unwrap();
        factory.update_texture(&texture, &image_info, &image,
                               Some(gfx::tex::TextureKind::Texture2D)).unwrap();
        if generate_mipmap {
            factory.generate_mipmap(&texture);
        }
        Texture {
            handle: texture
        }
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
    ) -> Self
        where F: gfx::Factory<R>
    {
        let width = if width == 0 { 1 } else { width };
        let height = if height == 0 { 1 } else { height };

        let mut pixels = vec![];
        for alpha in buffer {
            pixels.extend(vec![255; 3]);
            pixels.push(*alpha);
        }

        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: gfx::tex::RGBA8,
        };

        let image_info = texture_info.to_image_info();
        let texture = factory.create_texture(texture_info).unwrap();
        factory.update_texture(&texture, &image_info, &pixels,
                               Some(gfx::tex::TextureKind::Texture2D)).unwrap();
        Texture {
            handle: texture
        }
    }

    /// Updates the texture with an image.
    pub fn update<F>(&mut self, factory: &mut F, image: &RgbaImage)
        where F: gfx::Factory<R>
    {
        factory.update_texture(&self.handle,
            &self.handle.get_info().to_image_info(),
            &image,
            Some(gfx::tex::TextureKind::Texture2D)
        ).unwrap();
    }
}

impl<R> ImageSize for Texture<R> where R: gfx::Resources {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let info = self.handle.get_info();
        (info.width as u32, info.height as u32)
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use byteorder::{BigEndian, WriteBytesExt};
use {FarbfeldResult, FarbfeldError};

/// A farbfeld encoder
#[derive(Debug)]
pub struct FarbfeldEncoder<W: Write>(pub W);

impl<W: Write> FarbfeldEncoder<W> {
    /// Encodes a image with `width`, `height` and `data` into a farbfeld.
    /// # Failures
    /// Returns a `FarbfeldError::NotEnoughData` if the provided `data` slice is too short.
    pub fn encode(self, width: u32, height: u32, data: &[u8]) -> FarbfeldResult<()> {
        let mut w = self.0;
        let len = (width * height) as usize * 4;
        if data.len() < len { return Err(FarbfeldError::NotEnoughData) }
        w.write_all("farbfeld".as_bytes())?;
        w.write_u32::<BigEndian>(width)?;
        w.write_u32::<BigEndian>(height)?;
        w.write_all(data)?;
        Ok(())
    }
}
<commit_msg>replace call to as_bytes() with b"" syntax<commit_after>use std::io::Write;
use byteorder::{BigEndian, WriteBytesExt};
use {FarbfeldResult, FarbfeldError};

/// A farbfeld encoder
#[derive(Debug)]
pub struct FarbfeldEncoder<W: Write>(pub W);

impl<W: Write> FarbfeldEncoder<W> {
    /// Encodes a image with `width`, `height` and `data` into a farbfeld.
    /// # Failures
    /// Returns a `FarbfeldError::NotEnoughData` if the provided `data` slice is too short.
    pub fn encode(self, width: u32, height: u32, data: &[u8]) -> FarbfeldResult<()> {
        let mut w = self.0;
        let len = (width * height) as usize * 4;
        if data.len() < len { return Err(FarbfeldError::NotEnoughData) }
        w.write_all(b"farbfeld")?;
        w.write_u32::<BigEndian>(width)?;
        w.write_u32::<BigEndian>(height)?;
        w.write_all(data)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use handler::Handler;
use communication::Sender;

/// A trait for creating new WebSocket handlers.
pub trait Factory {
    type Handler: Handler;

    /// Called when a TCP connection is made.
    fn connection_made(&mut self, Sender) -> Self::Handler;

    /// Called when the WebSocket is shutting down.
    #[inline]
    fn on_shutdown(&mut self) {
        debug!("Factory received WebSocket shutdown request.");
    }

    /// Called when a new connection is established for a client endpoint.
    /// This method can be used to differentiate a client aspect for a handler.
    ///
    /// ```
    /// use ws::{Sender, Factory, Handler};
    ///
    /// struct MyHandler {
    ///     ws: Sender,
    ///     is_client: bool,
    /// }
    ///
    /// impl Handler for MyHandler {}
    ///
    /// struct MyFactory;
    ///
    /// impl Factory for MyFactory {
    ///     type Handler = MyHandler;
    ///
    ///     fn connection_made(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             // default to server
    ///             is_client: false,
    ///         }
    ///     }
    ///
    ///     fn client_connected(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             is_client: true,
    ///         }
    ///     }
    /// }
    /// ```
    #[inline]
    fn client_connected(&mut self, ws: Sender) -> Self::Handler {
        self.connection_made(ws)
    }

    /// Called when a new connection is established for a server endpoint.
    /// This method can be used to differentiate a server aspect for a handler.
    ///
    /// ```
    /// use ws::{Sender, Factory, Handler};
    ///
    /// struct MyHandler {
    ///     ws: Sender,
    ///     is_server: bool,
    /// }
    ///
    /// impl Handler for MyHandler {}
    ///
    /// struct MyFactory;
    ///
    /// impl Factory for MyFactory {
    ///     type Handler = MyHandler;
    ///
    ///     fn connection_made(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             // default to client
    ///             is_server: false,
    ///         }
    ///     }
    ///
    ///     fn server_connected(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             is_server: true,
    ///         }
    ///     }
    /// }
    #[inline]
    fn server_connected(&mut self, ws: Sender) -> Self::Handler {
        self.connection_made(ws)
    }

    /// Called when a TCP connection is lost with the handler that was
    /// setup for that connection.
    ///
    /// The default implementation is a noop that simply drops the handler.
    /// You can use this to track connections being destroyed or to finalize
    /// state that was not internally tracked by the handler.
    #[inline]
    fn connection_lost(&mut self, _: Self::Handler) {
    }

}

impl<F, H> Factory for F
    where H: Handler, F: FnMut(Sender) -> H
{
    type Handler = H;

    fn connection_made(&mut self, out: Sender) -> H {
        self(out)
    }

}

mod test {
    #![allow(unused_imports, unused_variables, dead_code)]
    use super::*;
    use mio;
    use communication::{Command, Sender};
    use handshake::{Request, Response, Handshake};
    use protocol::CloseCode;
    use frame;
    use message;
    use handler::Handler;
    use result::Result;

    struct S;

    impl mio::Handler for S {
        type Message = Command;
        type Timeout = ();
    }

    #[derive(Debug, Eq, PartialEq)]
    struct M;
    impl Handler for M {
        fn on_message(&mut self, _: message::Message) -> Result<()> {
            Ok(println!("test"))
        }

        fn on_frame(&mut self, f: frame::Frame) -> Result<Option<frame::Frame>> {
            Ok(None)
        }
    }

    #[test]
    fn test_impl_factory() {

        struct X;

        impl Factory for X {
            type Handler = M;
            fn connection_made(&mut self, _: Sender) -> M {
                M
            }
        }

        let event_loop = mio::EventLoop::<S>::new().unwrap();

        let mut x = X;
        let m = x.connection_made(
            Sender::new(mio::Token(0), event_loop.channel())
        );
        assert_eq!(m, M);
    }

    #[test]
    fn test_closure_factory() {
        let event_loop = mio::EventLoop::<S>::new().unwrap();

        let mut factory = |_| {
            |_| {Ok(())}
        };

        factory.connection_made(
            Sender::new(mio::Token(0), event_loop.channel())
        );
    }

    #[test]
    fn connection_lost() {
        struct X;

        impl Factory for X {
            type Handler = M;
            fn connection_made(&mut self, _: Sender) -> M {
                M
            }
            fn connection_lost(&mut self, handler: M) {
                assert_eq!(handler, M);
            }
        }

        let event_loop = mio::EventLoop::<S>::new().unwrap();

        let mut x = X;
        let m = x.connection_made(
            Sender::new(mio::Token(0), event_loop.channel())
        );
        x.connection_lost(m);
    }
}
<commit_msg>Fixed named argument in Factory::connection_made<commit_after>use handler::Handler;
use communication::Sender;

/// A trait for creating new WebSocket handlers.
pub trait Factory {
    type Handler: Handler;

    /// Called when a TCP connection is made.
    fn connection_made(&mut self, _: Sender) -> Self::Handler;

    /// Called when the WebSocket is shutting down.
    #[inline]
    fn on_shutdown(&mut self) {
        debug!("Factory received WebSocket shutdown request.");
    }

    /// Called when a new connection is established for a client endpoint.
    /// This method can be used to differentiate a client aspect for a handler.
    ///
    /// ```
    /// use ws::{Sender, Factory, Handler};
    ///
    /// struct MyHandler {
    ///     ws: Sender,
    ///     is_client: bool,
    /// }
    ///
    /// impl Handler for MyHandler {}
    ///
    /// struct MyFactory;
    ///
    /// impl Factory for MyFactory {
    ///     type Handler = MyHandler;
    ///
    ///     fn connection_made(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             // default to server
    ///             is_client: false,
    ///         }
    ///     }
    ///
    ///     fn client_connected(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             is_client: true,
    ///         }
    ///     }
    /// }
    /// ```
    #[inline]
    fn client_connected(&mut self, ws: Sender) -> Self::Handler {
        self.connection_made(ws)
    }

    /// Called when a new connection is established for a server endpoint.
    /// This method can be used to differentiate a server aspect for a handler.
    ///
    /// ```
    /// use ws::{Sender, Factory, Handler};
    ///
    /// struct MyHandler {
    ///     ws: Sender,
    ///     is_server: bool,
    /// }
    ///
    /// impl Handler for MyHandler {}
    ///
    /// struct MyFactory;
    ///
    /// impl Factory for MyFactory {
    ///     type Handler = MyHandler;
    ///
    ///     fn connection_made(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             // default to client
    ///             is_server: false,
    ///         }
    ///     }
    ///
    ///     fn server_connected(&mut self, ws: Sender) -> MyHandler {
    ///         MyHandler {
    ///             ws: ws,
    ///             is_server: true,
    ///         }
    ///     }
    /// }
    #[inline]
    fn server_connected(&mut self, ws: Sender) -> Self::Handler {
        self.connection_made(ws)
    }

    /// Called when a TCP connection is lost with the handler that was
    /// setup for that connection.
    ///
    /// The default implementation is a noop that simply drops the handler.
    /// You can use this to track connections being destroyed or to finalize
    /// state that was not internally tracked by the handler.
    #[inline]
    fn connection_lost(&mut self, _: Self::Handler) {
    }

}

impl<F, H> Factory for F
    where H: Handler, F: FnMut(Sender) -> H
{
    type Handler = H;

    fn connection_made(&mut self, out: Sender) -> H {
        self(out)
    }

}

mod test {
    #![allow(unused_imports, unused_variables, dead_code)]
    use super::*;
    use mio;
    use communication::{Command, Sender};
    use handshake::{Request, Response, Handshake};
    use protocol::CloseCode;
    use frame;
    use message;
    use handler::Handler;
    use result::Result;

    struct S;

    impl mio::Handler for S {
        type Message = Command;
        type Timeout = ();
    }

    #[derive(Debug, Eq, PartialEq)]
    struct M;
    impl Handler for M {
        fn on_message(&mut self, _: message::Message) -> Result<()> {
            Ok(println!("test"))
        }

        fn on_frame(&mut self, f: frame::Frame) -> Result<Option<frame::Frame>> {
            Ok(None)
        }
    }

    #[test]
    fn test_impl_factory() {

        struct X;

        impl Factory for X {
            type Handler = M;
            fn connection_made(&mut self, _: Sender) -> M {
                M
            }
        }

        let event_loop = mio::EventLoop::<S>::new().unwrap();

        let mut x = X;
        let m = x.connection_made(
            Sender::new(mio::Token(0), event_loop.channel())
        );
        assert_eq!(m, M);
    }

    #[test]
    fn test_closure_factory() {
        let event_loop = mio::EventLoop::<S>::new().unwrap();

        let mut factory = |_| {
            |_| {Ok(())}
        };

        factory.connection_made(
            Sender::new(mio::Token(0), event_loop.channel())
        );
    }

    #[test]
    fn connection_lost() {
        struct X;

        impl Factory for X {
            type Handler = M;
            fn connection_made(&mut self, _: Sender) -> M {
                M
            }
            fn connection_lost(&mut self, handler: M) {
                assert_eq!(handler, M);
            }
        }

        let event_loop = mio::EventLoop::<S>::new().unwrap();

        let mut x = X;
        let m = x.connection_made(
            Sender::new(mio::Token(0), event_loop.channel())
        );
        x.connection_lost(m);
    }
}
<|endoftext|>


<commit_before>use crate::*;
use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize};
use utils::{u8_from_hex_str, u8_to_hex_str};

/// Each of the BLS signature domains.
///
/// Spec v0.8.1
pub enum Domain {
    BeaconProposer,
    Randao,
    Attestation,
    Deposit,
    VoluntaryExit,
    Transfer,
}

/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.8.1
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChainSpec {
    /*
     * Constants
     */
    #[serde(skip_serializing)] // skipped because Serde TOML has trouble with u64::max
    pub far_future_epoch: Epoch,
    pub base_rewards_per_epoch: u64,
    pub deposit_contract_tree_depth: u64,
    pub seconds_per_day: u64,

    /*
     * Misc
     */
    pub target_committee_size: usize,
    pub min_per_epoch_churn_limit: u64,
    pub churn_limit_quotient: u64,
    pub shuffle_round_count: u8,
    pub min_genesis_active_validator_count: u64,
    pub min_genesis_time: u64,

    /*
     *  Gwei values
     */
    pub min_deposit_amount: u64,
    pub max_effective_balance: u64,
    pub ejection_balance: u64,
    pub effective_balance_increment: u64,

    /*
     * Initial Values
     */
    pub genesis_slot: Slot,
    #[serde(deserialize_with = "u8_from_hex_str", serialize_with = "u8_to_hex_str")]
    pub bls_withdrawal_prefix_byte: u8,

    /*
     * Time parameters
     */
    pub seconds_per_slot: u64,
    pub min_attestation_inclusion_delay: u64,
    pub min_seed_lookahead: Epoch,
    pub activation_exit_delay: u64,
    pub min_validator_withdrawability_delay: Epoch,
    pub persistent_committee_period: u64,
    pub max_epochs_per_crosslink: u64,
    pub min_epochs_to_inactivity_penalty: u64,

    /*
     * Reward and penalty quotients
     */
    pub base_reward_factor: u64,
    pub whistleblower_reward_quotient: u64,
    pub proposer_reward_quotient: u64,
    pub inactivity_penalty_quotient: u64,
    pub min_slashing_penalty_quotient: u64,

    /*
     * Signature domains
     *
     * Fields should be private to prevent accessing a domain that hasn't been modified to suit
     * some `Fork`.
     *
     * Use `ChainSpec::get_domain(..)` to access these values.
     */
    domain_beacon_proposer: u32,
    domain_randao: u32,
    domain_attestation: u32,
    domain_deposit: u32,
    domain_voluntary_exit: u32,
    domain_transfer: u32,

    pub boot_nodes: Vec<String>,
    pub network_id: u8,
}

impl ChainSpec {
    /// Get the domain number that represents the fork meta and signature domain.
    ///
    /// Spec v0.8.1
    pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 {
        let domain_constant = match domain {
            Domain::BeaconProposer => self.domain_beacon_proposer,
            Domain::Randao => self.domain_randao,
            Domain::Attestation => self.domain_attestation,
            Domain::Deposit => self.domain_deposit,
            Domain::VoluntaryExit => self.domain_voluntary_exit,
            Domain::Transfer => self.domain_transfer,
        };

        let mut bytes: Vec<u8> = int_to_bytes4(domain_constant);
        bytes.append(&mut fork.get_fork_version(epoch).to_vec());

        let mut fork_and_domain = [0; 8];
        fork_and_domain.copy_from_slice(&bytes);

        u64::from_le_bytes(fork_and_domain)
    }

    /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
    ///
    /// Spec v0.8.1
    pub fn mainnet() -> Self {
        Self {
            /*
             * Constants
             */
            far_future_epoch: Epoch::new(u64::max_value()),
            base_rewards_per_epoch: 5,
            deposit_contract_tree_depth: 32,
            seconds_per_day: 86400,

            /*
             * Misc
             */
            target_committee_size: 128,
            min_per_epoch_churn_limit: 4,
            churn_limit_quotient: 65_536,
            shuffle_round_count: 90,
            min_genesis_active_validator_count: 65_536,
            min_genesis_time: 1_578_009_600, // Jan 3, 2020

            /*
             *  Gwei values
             */
            min_deposit_amount: u64::pow(2, 0) * u64::pow(10, 9),
            max_effective_balance: u64::pow(2, 5) * u64::pow(10, 9),
            ejection_balance: u64::pow(2, 4) * u64::pow(10, 9),
            effective_balance_increment: u64::pow(2, 0) * u64::pow(10, 9),

            /*
             * Initial Values
             */
            genesis_slot: Slot::new(0),
            bls_withdrawal_prefix_byte: 0,

            /*
             * Time parameters
             */
            seconds_per_slot: 6,
            min_attestation_inclusion_delay: 1,
            min_seed_lookahead: Epoch::new(1),
            activation_exit_delay: 4,
            min_validator_withdrawability_delay: Epoch::new(256),
            persistent_committee_period: 2_048,
            max_epochs_per_crosslink: 64,
            min_epochs_to_inactivity_penalty: 4,

            /*
             * Reward and penalty quotients
             */
            base_reward_factor: 64,
            whistleblower_reward_quotient: 512,
            proposer_reward_quotient: 8,
            inactivity_penalty_quotient: 33_554_432,
            min_slashing_penalty_quotient: 32,

            /*
             * Signature domains
             */
            domain_beacon_proposer: 0,
            domain_randao: 1,
            domain_attestation: 2,
            domain_deposit: 3,
            domain_voluntary_exit: 4,
            domain_transfer: 5,

            /*
             * Network specific
             */
            boot_nodes: vec![],
            network_id: 1, // mainnet network id
        }
    }

    /// Ethereum Foundation minimal spec, as defined here:
    ///
    /// https://github.com/ethereum/eth2.0-specs/blob/v0.8.1/configs/constant_presets/minimal.yaml
    ///
    /// Spec v0.8.1
    pub fn minimal() -> Self {
        // Note: bootnodes to be updated when static nodes exist.
        let boot_nodes = vec![];
        let genesis_slot = Slot::new(0);

        Self {
            target_committee_size: 4,
            shuffle_round_count: 10,
            min_genesis_active_validator_count: 64,
            max_epochs_per_crosslink: 4,
            min_attestation_inclusion_delay: 2,
            genesis_slot,
            network_id: 2, // lighthouse testnet network id
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }

    /// Interop testing spec
    ///
    /// This allows us to customize a chain spec for interop testing.
    pub fn interop() -> Self {
        let genesis_slot = Slot::new(0);
        let boot_nodes = vec![];

        Self {
            seconds_per_slot: 12,
            target_committee_size: 4,
            shuffle_round_count: 10,
            min_attestation_inclusion_delay: 2,
            genesis_slot,
            network_id: 13,
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }
}

impl Default for ChainSpec {
    fn default() -> Self {
        Self::mainnet()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use int_to_bytes::int_to_bytes8;

    #[test]
    fn test_mainnet_spec_can_be_constructed() {
        let _ = ChainSpec::mainnet();
    }

    fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) {
        let fork = Fork::genesis(Epoch::new(0));
        let epoch = Epoch::new(0);

        let domain = spec.get_domain(epoch, domain_type, &fork);

        let mut expected = int_to_bytes4(raw_domain);
        expected.append(&mut fork.get_fork_version(epoch).to_vec());

        assert_eq!(int_to_bytes8(domain), expected);
    }

    #[test]
    fn test_get_domain() {
        let spec = ChainSpec::mainnet();

        test_domain(Domain::BeaconProposer, spec.domain_beacon_proposer, &spec);
        test_domain(Domain::Randao, spec.domain_randao, &spec);
        test_domain(Domain::Attestation, spec.domain_attestation, &spec);
        test_domain(Domain::Deposit, spec.domain_deposit, &spec);
        test_domain(Domain::VoluntaryExit, spec.domain_voluntary_exit, &spec);
        test_domain(Domain::Transfer, spec.domain_transfer, &spec);
    }
}
<commit_msg>Correct minimal chainspec modifications<commit_after>use crate::*;
use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize};
use utils::{u8_from_hex_str, u8_to_hex_str};

/// Each of the BLS signature domains.
///
/// Spec v0.8.1
pub enum Domain {
    BeaconProposer,
    Randao,
    Attestation,
    Deposit,
    VoluntaryExit,
    Transfer,
}

/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.8.1
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChainSpec {
    /*
     * Constants
     */
    #[serde(skip_serializing)] // skipped because Serde TOML has trouble with u64::max
    pub far_future_epoch: Epoch,
    pub base_rewards_per_epoch: u64,
    pub deposit_contract_tree_depth: u64,
    pub seconds_per_day: u64,

    /*
     * Misc
     */
    pub target_committee_size: usize,
    pub min_per_epoch_churn_limit: u64,
    pub churn_limit_quotient: u64,
    pub shuffle_round_count: u8,
    pub min_genesis_active_validator_count: u64,
    pub min_genesis_time: u64,

    /*
     *  Gwei values
     */
    pub min_deposit_amount: u64,
    pub max_effective_balance: u64,
    pub ejection_balance: u64,
    pub effective_balance_increment: u64,

    /*
     * Initial Values
     */
    pub genesis_slot: Slot,
    #[serde(deserialize_with = "u8_from_hex_str", serialize_with = "u8_to_hex_str")]
    pub bls_withdrawal_prefix_byte: u8,

    /*
     * Time parameters
     */
    pub seconds_per_slot: u64,
    pub min_attestation_inclusion_delay: u64,
    pub min_seed_lookahead: Epoch,
    pub activation_exit_delay: u64,
    pub min_validator_withdrawability_delay: Epoch,
    pub persistent_committee_period: u64,
    pub max_epochs_per_crosslink: u64,
    pub min_epochs_to_inactivity_penalty: u64,

    /*
     * Reward and penalty quotients
     */
    pub base_reward_factor: u64,
    pub whistleblower_reward_quotient: u64,
    pub proposer_reward_quotient: u64,
    pub inactivity_penalty_quotient: u64,
    pub min_slashing_penalty_quotient: u64,

    /*
     * Signature domains
     *
     * Fields should be private to prevent accessing a domain that hasn't been modified to suit
     * some `Fork`.
     *
     * Use `ChainSpec::get_domain(..)` to access these values.
     */
    domain_beacon_proposer: u32,
    domain_randao: u32,
    domain_attestation: u32,
    domain_deposit: u32,
    domain_voluntary_exit: u32,
    domain_transfer: u32,

    pub boot_nodes: Vec<String>,
    pub network_id: u8,
}

impl ChainSpec {
    /// Get the domain number that represents the fork meta and signature domain.
    ///
    /// Spec v0.8.1
    pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 {
        let domain_constant = match domain {
            Domain::BeaconProposer => self.domain_beacon_proposer,
            Domain::Randao => self.domain_randao,
            Domain::Attestation => self.domain_attestation,
            Domain::Deposit => self.domain_deposit,
            Domain::VoluntaryExit => self.domain_voluntary_exit,
            Domain::Transfer => self.domain_transfer,
        };

        let mut bytes: Vec<u8> = int_to_bytes4(domain_constant);
        bytes.append(&mut fork.get_fork_version(epoch).to_vec());

        let mut fork_and_domain = [0; 8];
        fork_and_domain.copy_from_slice(&bytes);

        u64::from_le_bytes(fork_and_domain)
    }

    /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
    ///
    /// Spec v0.8.1
    pub fn mainnet() -> Self {
        Self {
            /*
             * Constants
             */
            far_future_epoch: Epoch::new(u64::max_value()),
            base_rewards_per_epoch: 5,
            deposit_contract_tree_depth: 32,
            seconds_per_day: 86400,

            /*
             * Misc
             */
            target_committee_size: 128,
            min_per_epoch_churn_limit: 4,
            churn_limit_quotient: 65_536,
            shuffle_round_count: 90,
            min_genesis_active_validator_count: 65_536,
            min_genesis_time: 1_578_009_600, // Jan 3, 2020

            /*
             *  Gwei values
             */
            min_deposit_amount: u64::pow(2, 0) * u64::pow(10, 9),
            max_effective_balance: u64::pow(2, 5) * u64::pow(10, 9),
            ejection_balance: u64::pow(2, 4) * u64::pow(10, 9),
            effective_balance_increment: u64::pow(2, 0) * u64::pow(10, 9),

            /*
             * Initial Values
             */
            genesis_slot: Slot::new(0),
            bls_withdrawal_prefix_byte: 0,

            /*
             * Time parameters
             */
            seconds_per_slot: 6,
            min_attestation_inclusion_delay: 1,
            min_seed_lookahead: Epoch::new(1),
            activation_exit_delay: 4,
            min_validator_withdrawability_delay: Epoch::new(256),
            persistent_committee_period: 2_048,
            max_epochs_per_crosslink: 64,
            min_epochs_to_inactivity_penalty: 4,

            /*
             * Reward and penalty quotients
             */
            base_reward_factor: 64,
            whistleblower_reward_quotient: 512,
            proposer_reward_quotient: 8,
            inactivity_penalty_quotient: 33_554_432,
            min_slashing_penalty_quotient: 32,

            /*
             * Signature domains
             */
            domain_beacon_proposer: 0,
            domain_randao: 1,
            domain_attestation: 2,
            domain_deposit: 3,
            domain_voluntary_exit: 4,
            domain_transfer: 5,

            /*
             * Network specific
             */
            boot_nodes: vec![],
            network_id: 1, // mainnet network id
        }
    }

    /// Ethereum Foundation minimal spec, as defined here:
    ///
    /// https://github.com/ethereum/eth2.0-specs/blob/v0.8.1/configs/constant_presets/minimal.yaml
    ///
    /// Spec v0.8.1
    pub fn minimal() -> Self {
        // Note: bootnodes to be updated when static nodes exist.
        let boot_nodes = vec![];

        Self {
            target_committee_size: 4,
            shuffle_round_count: 10,
            min_genesis_active_validator_count: 64,
            max_epochs_per_crosslink: 4,
            network_id: 2, // lighthouse testnet network id
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }

    /// Interop testing spec
    ///
    /// This allows us to customize a chain spec for interop testing.
    pub fn interop() -> Self {
        let boot_nodes = vec![];

        Self {
            seconds_per_slot: 12,
            target_committee_size: 4,
            shuffle_round_count: 10,
            network_id: 13,
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }
}

impl Default for ChainSpec {
    fn default() -> Self {
        Self::mainnet()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use int_to_bytes::int_to_bytes8;

    #[test]
    fn test_mainnet_spec_can_be_constructed() {
        let _ = ChainSpec::mainnet();
    }

    fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) {
        let fork = Fork::genesis(Epoch::new(0));
        let epoch = Epoch::new(0);

        let domain = spec.get_domain(epoch, domain_type, &fork);

        let mut expected = int_to_bytes4(raw_domain);
        expected.append(&mut fork.get_fork_version(epoch).to_vec());

        assert_eq!(int_to_bytes8(domain), expected);
    }

    #[test]
    fn test_get_domain() {
        let spec = ChainSpec::mainnet();

        test_domain(Domain::BeaconProposer, spec.domain_beacon_proposer, &spec);
        test_domain(Domain::Randao, spec.domain_randao, &spec);
        test_domain(Domain::Attestation, spec.domain_attestation, &spec);
        test_domain(Domain::Deposit, spec.domain_deposit, &spec);
        test_domain(Domain::VoluntaryExit, spec.domain_voluntary_exit, &spec);
        test_domain(Domain::Transfer, spec.domain_transfer, &spec);
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::time::Duration;

use parking_lot::{Condvar, Mutex};

use super::*;

#[derive(Debug, Clone, Copy)]
pub(crate) enum ShutdownState {
    Running,
    ShuttingDown,
    ShutDown,
}

impl ShutdownState {
    fn is_running(self) -> bool {
        if let ShutdownState::Running = self { true } else { false }
    }

    fn is_shutdown(self) -> bool {
        if let ShutdownState::ShutDown = self { true } else { false }
    }
}

#[derive(Debug)]
pub(crate) struct Flusher {
    shutdown: Arc<Mutex<ShutdownState>>,
    sc: Arc<Condvar>,
    join_handle: Mutex<Option<std::thread::JoinHandle<()>>>,
}

impl Flusher {
    /// Spawns a thread that periodically calls `callback` until dropped.
    pub(crate) fn new(
        name: String,
        pagecache: Arc<PageCache>,
        flush_every_ms: u64,
    ) -> Self {
        #[allow(clippy::mutex_atomic)] // mutex used in CondVar below
        let shutdown = Arc::new(Mutex::new(ShutdownState::Running));
        let sc = Arc::new(Condvar::new());

        let join_handle = thread::Builder::new()
            .name(name)
            .spawn({
                let shutdown = shutdown.clone();
                let sc = sc.clone();
                move || run(&shutdown, &sc, &pagecache, flush_every_ms)
            })
            .unwrap();

        Self { shutdown, sc, join_handle: Mutex::new(Some(join_handle)) }
    }
}

fn run(
    shutdown: &Arc<Mutex<ShutdownState>>,
    sc: &Arc<Condvar>,
    pagecache: &Arc<PageCache>,
    flush_every_ms: u64,
) {
    let flush_every = Duration::from_millis(flush_every_ms);
    let mut shutdown = shutdown.lock();
    let mut wrote_data = false;
    while shutdown.is_running() || wrote_data {
        let before = std::time::Instant::now();
        let cc = concurrency_control::read();
        match pagecache.log.roll_iobuf() {
            Ok(0) => {
                wrote_data = false;
                if !shutdown.is_running() {
                    break;
                }
            }
            Ok(_) => {
                wrote_data = true;
                if !shutdown.is_running() {
                    // loop right away if we're in
                    // shutdown mode, to flush data
                    // more quickly.
                    continue;
                }
            }
            Err(e) => {
                error!("failed to flush from periodic flush thread: {}", e);

                #[cfg(feature = "failpoints")]
                pagecache.set_failpoint(e);

                *shutdown = ShutdownState::ShutDown;

                // having held the mutex makes this linearized
                // with the notify below.
                drop(shutdown);

                let _notified = sc.notify_all();
                return;
            }
        }
        drop(cc);

        // so we can spend a little effort
        // cleaning up the segments. try not to
        // spend more than half of our sleep
        // time rewriting pages though.
        //
        // this looks weird because it's a rust-style do-while
        // where the conditional is the full body
        while {
            let made_progress = match pagecache.attempt_gc() {
                Err(e) => {
                    error!(
                        "failed to clean file from periodic flush thread: {}",
                        e
                    );

                    #[cfg(feature = "failpoints")]
                    pagecache.set_failpoint(e);

                    *shutdown = ShutdownState::ShutDown;

                    // having held the mutex makes this linearized
                    // with the notify below.
                    drop(shutdown);

                    let _notified = sc.notify_all();
                    return;
                }
                Ok(false) => false,
                Ok(true) => true,
            };
            made_progress
                && shutdown.is_running()
                && before.elapsed() < flush_every / 2
        } {}

        if let Err(e) = pagecache.config.file.sync_all() {
            error!("failed to fsync from periodic flush thread: {}", e);
        }

        let sleep_duration = flush_every
            .checked_sub(before.elapsed())
            .unwrap_or_else(|| Duration::from_millis(1));

        if shutdown.is_running() {
            // only sleep before the next flush if we are
            // running normally. if we're shutting down,
            // flush faster.
            sc.wait_for(&mut shutdown, sleep_duration);
        }
    }

    *shutdown = ShutdownState::ShutDown;

    // having held the mutex makes this linearized
    // with the notify below.
    drop(shutdown);

    let _notified = sc.notify_all();
}

impl Drop for Flusher {
    fn drop(&mut self) {
        let mut shutdown = self.shutdown.lock();
        if shutdown.is_running() {
            *shutdown = ShutdownState::ShuttingDown;
            let _notified = self.sc.notify_all();
        }

        let mut _count = 0;
        while !shutdown.is_shutdown() {
            let _ = self.sc.wait_for(&mut shutdown, Duration::from_millis(100));
            _count += 1;

            testing_assert!(_count < 5);
        }

        let mut join_handle_opt = self.join_handle.lock();
        if let Some(join_handle) = join_handle_opt.take() {
            if let Err(e) = join_handle.join() {
                error!("error joining Periodic thread: {:?}", e);
            }
        }
    }
}
<commit_msg>Avoid underscored variable<commit_after>use std::thread;
use std::time::Duration;

use parking_lot::{Condvar, Mutex};

use super::*;

#[derive(Debug, Clone, Copy)]
pub(crate) enum ShutdownState {
    Running,
    ShuttingDown,
    ShutDown,
}

impl ShutdownState {
    fn is_running(self) -> bool {
        if let ShutdownState::Running = self { true } else { false }
    }

    fn is_shutdown(self) -> bool {
        if let ShutdownState::ShutDown = self { true } else { false }
    }
}

#[derive(Debug)]
pub(crate) struct Flusher {
    shutdown: Arc<Mutex<ShutdownState>>,
    sc: Arc<Condvar>,
    join_handle: Mutex<Option<std::thread::JoinHandle<()>>>,
}

impl Flusher {
    /// Spawns a thread that periodically calls `callback` until dropped.
    pub(crate) fn new(
        name: String,
        pagecache: Arc<PageCache>,
        flush_every_ms: u64,
    ) -> Self {
        #[allow(clippy::mutex_atomic)] // mutex used in CondVar below
        let shutdown = Arc::new(Mutex::new(ShutdownState::Running));
        let sc = Arc::new(Condvar::new());

        let join_handle = thread::Builder::new()
            .name(name)
            .spawn({
                let shutdown = shutdown.clone();
                let sc = sc.clone();
                move || run(&shutdown, &sc, &pagecache, flush_every_ms)
            })
            .unwrap();

        Self { shutdown, sc, join_handle: Mutex::new(Some(join_handle)) }
    }
}

fn run(
    shutdown: &Arc<Mutex<ShutdownState>>,
    sc: &Arc<Condvar>,
    pagecache: &Arc<PageCache>,
    flush_every_ms: u64,
) {
    let flush_every = Duration::from_millis(flush_every_ms);
    let mut shutdown = shutdown.lock();
    let mut wrote_data = false;
    while shutdown.is_running() || wrote_data {
        let before = std::time::Instant::now();
        let cc = concurrency_control::read();
        match pagecache.log.roll_iobuf() {
            Ok(0) => {
                wrote_data = false;
                if !shutdown.is_running() {
                    break;
                }
            }
            Ok(_) => {
                wrote_data = true;
                if !shutdown.is_running() {
                    // loop right away if we're in
                    // shutdown mode, to flush data
                    // more quickly.
                    continue;
                }
            }
            Err(e) => {
                error!("failed to flush from periodic flush thread: {}", e);

                #[cfg(feature = "failpoints")]
                pagecache.set_failpoint(e);

                *shutdown = ShutdownState::ShutDown;

                // having held the mutex makes this linearized
                // with the notify below.
                drop(shutdown);

                let _notified = sc.notify_all();
                return;
            }
        }
        drop(cc);

        // so we can spend a little effort
        // cleaning up the segments. try not to
        // spend more than half of our sleep
        // time rewriting pages though.
        //
        // this looks weird because it's a rust-style do-while
        // where the conditional is the full body
        while {
            let made_progress = match pagecache.attempt_gc() {
                Err(e) => {
                    error!(
                        "failed to clean file from periodic flush thread: {}",
                        e
                    );

                    #[cfg(feature = "failpoints")]
                    pagecache.set_failpoint(e);

                    *shutdown = ShutdownState::ShutDown;

                    // having held the mutex makes this linearized
                    // with the notify below.
                    drop(shutdown);

                    let _notified = sc.notify_all();
                    return;
                }
                Ok(false) => false,
                Ok(true) => true,
            };
            made_progress
                && shutdown.is_running()
                && before.elapsed() < flush_every / 2
        } {}

        if let Err(e) = pagecache.config.file.sync_all() {
            error!("failed to fsync from periodic flush thread: {}", e);
        }

        let sleep_duration = flush_every
            .checked_sub(before.elapsed())
            .unwrap_or_else(|| Duration::from_millis(1));

        if shutdown.is_running() {
            // only sleep before the next flush if we are
            // running normally. if we're shutting down,
            // flush faster.
            sc.wait_for(&mut shutdown, sleep_duration);
        }
    }

    *shutdown = ShutdownState::ShutDown;

    // having held the mutex makes this linearized
    // with the notify below.
    drop(shutdown);

    let _notified = sc.notify_all();
}

impl Drop for Flusher {
    fn drop(&mut self) {
        let mut shutdown = self.shutdown.lock();
        if shutdown.is_running() {
            *shutdown = ShutdownState::ShuttingDown;
            let _notified = self.sc.notify_all();
        }

        #[cfg(feature = "testing")]
        {
            let mut count = 0;
        }
        while !shutdown.is_shutdown() {
            let _ = self.sc.wait_for(&mut shutdown, Duration::from_millis(100));
            #[cfg(feature = "testing")]
            {
                count += 1;
            }

            testing_assert!(count < 5);
        }

        let mut join_handle_opt = self.join_handle.lock();
        if let Some(join_handle) = join_handle_opt.take() {
            if let Err(e) = join_handle.join() {
                error!("error joining Periodic thread: {:?}", e);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate yaml;

use std::collections::HashMap;
use std::fs::File;
use self::yaml::constructor::YamlStandardData;

fn unwrap_yaml_str(yaml_str: YamlStandardData) -> Option<String> {
  match yaml_str {
    YamlStandardData::YamlString(s) => Some(s),
    _ => None,
  }
}

pub struct TrTable {
  table: HashMap<char, Vec<String>>,
}

impl TrTable {
  /// Creates an empty TrTable
  fn new() -> TrTable {
    TrTable {
      table: HashMap::new()
    }
  }

  pub fn load(fname: &str) -> Result<TrTable, &'static str> {
    // open and load the file
    let mut fp = File::open(&fname)
      .ok()
      .expect("trtab file could not be found");
    let yaml_data = yaml::parse_io_utf8(&mut fp)
      .ok()
      .expect("could not parse trtab YAML");

    if yaml_data.is_empty() {
      return Err("YAML file did not contain any data")
    }

    // create a new TrTable that will be returned
    let mut trtab = TrTable::new();
    for yaml_datum in yaml_data {
      // get all items in the list
      let translations = match yaml_datum {
        YamlStandardData::YamlMapping(v) => v,
        _ => return Err("reached unexpected YAML data"),
      };

      for pair in translations {
        let key = unwrap_yaml_str(pair.0)
          .expect("Couldn't unwrap YAML key");
        let value = unwrap_yaml_str(pair.1)
          .expect("Couldn't unwrap YAML value");
        // verify that it's a single letter
        if key.len() != 1 {
          panic!("expected a single letter, but instead got '{}'", key);
        }
        // set the letter
        let letter: char = key
          .chars()
          .nth(0)
          .unwrap();
        // get all the words as a Vec<String>
        let mut words: Vec<String> = value.split(" ")
          .map(|s| s.to_string())
          .collect();

        // useful for debugging
        //println!("{} : {}", letter, words.connect(" - "));
        if trtab.table.contains_key(&letter) {
          // append the words to the thing
          trtab.table.get_mut(&letter)
            .unwrap()
            .extend(words);
        } else {
          trtab.table.insert(letter, words);
        }

      }
    }

    Ok(trtab)
  }
}<commit_msg>Wrapped the contains_key() and get() methods in the TrTable because that's all you need for a readonly table<commit_after>extern crate yaml;

use std::collections::HashMap;
use std::fs::File;
use self::yaml::constructor::YamlStandardData;

fn unwrap_yaml_str(yaml_str: YamlStandardData) -> Option<String> {
  match yaml_str {
    YamlStandardData::YamlString(s) => Some(s),
    _ => None,
  }
}

pub struct TrTable {
  table: HashMap<char, Vec<String>>,
}

impl TrTable {
  /// Creates an empty TrTable
  fn new() -> TrTable {
    TrTable {
      table: HashMap::new()
    }
  }

  pub fn contains_key(&self, letter: char) -> bool {
    self.table.contains_key(&letter)
  }

  pub fn get(&self, letter: char) -> Option<&Vec<String>> {
    self.table.get(&letter)
  }

  pub fn load(fname: &str) -> Result<TrTable, &'static str> {
    // open and load the file
    let mut fp = File::open(&fname)
      .ok()
      .expect("trtab file could not be found");
    let yaml_data = yaml::parse_io_utf8(&mut fp)
      .ok()
      .expect("could not parse trtab YAML");

    if yaml_data.is_empty() {
      return Err("YAML file did not contain any data")
    }

    // create a new TrTable that will be returned
    let mut trtab = TrTable::new();
    for yaml_datum in yaml_data {
      // get all items in the list
      let translations = match yaml_datum {
        YamlStandardData::YamlMapping(v) => v,
        _ => return Err("reached unexpected YAML data"),
      };

      for pair in translations {
        let key = unwrap_yaml_str(pair.0)
          .expect("Couldn't unwrap YAML key");
        let value = unwrap_yaml_str(pair.1)
          .expect("Couldn't unwrap YAML value");
        // verify that it's a single letter
        if key.len() != 1 {
          panic!("expected a single letter, but instead got '{}'", key);
        }
        // set the letter
        let letter: char = key
          .chars()
          .nth(0)
          .unwrap();
        // get all the words as a Vec<String>
        let mut words: Vec<String> = value.split(" ")
          .map(|s| s.to_string())
          .collect();

        // useful for debugging
        //println!("{} : {}", letter, words.connect(" - "));
        if trtab.table.contains_key(&letter) {
          // append the words to the thing
          trtab.table.get_mut(&letter)
            .unwrap()
            .extend(words);
        } else {
          trtab.table.insert(letter, words);
        }

      }
    }

    Ok(trtab)
  }
}<|endoftext|>


<commit_before>// Silence invalid warnings due to rust-lang/rust#16719
#![allow(improper_ctypes)]

use {Errno, Result};
use libc::{c_int, c_void, size_t, off_t};
use std::marker::PhantomData;
use std::os::unix::io::RawFd;

mod ffi {
    use super::IoVec;
    use libc::{ssize_t, c_int, size_t, off_t, c_void};
    use std::os::unix::io::RawFd;

    extern {
        // vectorized version of write
        // doc: http://man7.org/linux/man-pages/man2/writev.2.html
        pub fn writev(fd: RawFd, iov: *const IoVec<&[u8]>, iovcnt: c_int) -> ssize_t;

        // vectorized version of read
        // doc: http://man7.org/linux/man-pages/man2/readv.2.html
        pub fn readv(fd: RawFd, iov: *const IoVec<&mut [u8]>, iovcnt: c_int) -> ssize_t;

        // vectorized write at a specified offset
        // doc: http://man7.org/linux/man-pages/man2/pwritev.2.html
        #[cfg(feature = "preadv_pwritev")]
        pub fn pwritev(fd: RawFd, iov: *const IoVec<&[u8]>, iovcnt: c_int,
                       offset: off_t) -> ssize_t;

        // vectorized read at a specified offset
        // doc: http://man7.org/linux/man-pages/man2/preadv.2.html
        #[cfg(feature = "preadv_pwritev")]
        pub fn preadv(fd: RawFd, iov: *const IoVec<&mut [u8]>, iovcnt: c_int,
                      offset: off_t) -> ssize_t;

        // write to a file at a specified offset
        // doc: http://man7.org/linux/man-pages/man2/pwrite.2.html
        pub fn pwrite(fd: RawFd, buf: *const c_void, nbyte: size_t,
                      offset: off_t) -> ssize_t;

        // read from a file at a specified offset
        // doc: http://man7.org/linux/man-pages/man2/pread.2.html
        pub fn pread(fd: RawFd, buf: *mut c_void, nbyte: size_t, offset: off_t)
                     -> ssize_t;
    }
}

pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> {
    let res = unsafe { ffi::writev(fd, iov.as_ptr(), iov.len() as c_int) };

    Errno::result(res).map(|r| r as usize)
}

pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
    let res = unsafe { ffi::readv(fd, iov.as_ptr(), iov.len() as c_int) };

    Errno::result(res).map(|r| r as usize)
}

#[cfg(feature = "preadv_pwritev")]
pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
               offset: off_t) -> Result<usize> {
    let res = unsafe {
        ffi::pwritev(fd, iov.as_ptr(), iov.len() as c_int, offset)
    };

    Errno::result(res).map(|r| r as usize)
}

#[cfg(feature = "preadv_pwritev")]
pub fn preadv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>],
              offset: off_t) -> Result<usize> {
    let res = unsafe {
        ffi::preadv(fd, iov.as_ptr(), iov.len() as c_int, offset)
    };

    Errno::result(res).map(|r| r as usize)
}

pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
    let res = unsafe {
        ffi::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
                    offset)
    };

    Errno::result(res).map(|r| r as usize)
}

pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
    let res = unsafe {
        ffi::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t,
                   offset)
    };

    Errno::result(res).map(|r| r as usize)
}

#[repr(C)]
pub struct IoVec<T> {
    iov_base: *mut c_void,
    iov_len: size_t,
    phantom: PhantomData<T>
}

impl<T> IoVec<T> {
    #[inline]
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                self.iov_base as *const u8,
                self.iov_len as usize)
        }
    }
}

impl<'a> IoVec<&'a [u8]> {
    pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
        IoVec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
            phantom: PhantomData
        }
    }
}

impl<'a> IoVec<&'a mut [u8]> {
    pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
        IoVec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
            phantom: PhantomData
        }
    }
}

#[test]
pub fn test_size_of_io_vec() {
    use nixtest;
    nixtest::assert_size_of::<IoVec<&[u8]>>("iovec");
}
<commit_msg>uio: Use bindings from libc instead of our own<commit_after>// Silence invalid warnings due to rust-lang/rust#16719
#![allow(improper_ctypes)]

use {Errno, Result};
use libc::{self, c_int, c_void, size_t, off_t};
use std::marker::PhantomData;
use std::os::unix::io::RawFd;

pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> {
    let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };

    Errno::result(res).map(|r| r as usize)
}

pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
    let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };

    Errno::result(res).map(|r| r as usize)
}

#[cfg(feature = "preadv_pwritev")]
pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
               offset: off_t) -> Result<usize> {
    let res = unsafe {
        libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
    };

    Errno::result(res).map(|r| r as usize)
}

#[cfg(feature = "preadv_pwritev")]
pub fn preadv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>],
              offset: off_t) -> Result<usize> {
    let res = unsafe {
        libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
    };

    Errno::result(res).map(|r| r as usize)
}

pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
    let res = unsafe {
        libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
                    offset)
    };

    Errno::result(res).map(|r| r as usize)
}

pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
    let res = unsafe {
        libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t,
                   offset)
    };

    Errno::result(res).map(|r| r as usize)
}

#[repr(C)]
pub struct IoVec<T>(libc::iovec, PhantomData<T>);

impl<T> IoVec<T> {
    #[inline]
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                self.0.iov_base as *const u8,
                self.0.iov_len as usize)
        }
    }
}

impl<'a> IoVec<&'a [u8]> {
    pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
        IoVec(libc::iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
        }, PhantomData)
    }
}

impl<'a> IoVec<&'a mut [u8]> {
    pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
        IoVec(libc::iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t,
        }, PhantomData)
    }
}

#[test]
pub fn test_size_of_io_vec() {
    use nixtest;
    nixtest::assert_size_of::<IoVec<&[u8]>>("iovec");
}
<|endoftext|>


<commit_before>use game::{Game, GameStore};
use iron::prelude::*;
use iron::status;
use outcome::Outcome;
use persistent::{Read, Write};
use rand::{Rng, thread_rng};
use request::Data;
use words::WordList;
use serde::ser::Serialize;
use serde_json::to_string as serialize;

pub fn check(req: &mut Request) -> IronResult<Response> {
    let token = req.token()?.to_owned();
    let mutex = req.get::<Write<GameStore>>().expect("gamestore not found");

    let mut games = mutex.lock().expect("unable to lock mutex");
    let game = games.entry(token).or_insert_with(|| Game::new(select_word(req)));

    if game.outcome() != Outcome::InProgress {
        *game = Game::new(select_word(req));
    }

    Ok(create_response(&game.check()))
}

pub fn guess(req: &mut Request) -> IronResult<Response> {
    let token = req.token()?.to_owned();
    let guess = req.guess()?;
    let mutex = req.get::<Write<GameStore>>().expect("gamestore not found");

    let mut games = mutex.lock().expect("unable to lock mutex");
    let mut game = games.entry(token).or_insert_with(|| Game::new(select_word(req)));

    if game.outcome() != Outcome::InProgress {
        *game = Game::new(select_word(req));
    }

    Ok(create_response(&game.guess(&guess)))
}

fn create_response<T: Serialize>(model: &T) -> Response {
    use iron::headers::ContentType;

    let mut response = Response::with((
        status::Ok,
        serialize(model).unwrap(),
    ));
    response.headers.set(ContentType::json());
    response
}

fn select_word(req: &mut Request) -> String {
    let word_list = req.get::<Read<WordList>>().expect("wordlist not found");
    thread_rng().choose(&word_list).map_or("apple".to_owned(), |word| word.to_owned())
}<commit_msg>Scouting<commit_after>use game::{Game, GameStore};
use iron::prelude::*;
use iron::status;
use outcome::Outcome;
use persistent::{Read, Write};
use request::Data;
use serde::ser::Serialize;
use serde_json::to_string as serialize;

pub fn check(req: &mut Request) -> IronResult<Response> {
    let token = req.token()?.to_owned();
    let mutex = req.get::<Write<GameStore>>().expect("gamestore not found");

    let mut games = mutex.lock().expect("unable to lock mutex");
    let game = games.entry(token).or_insert_with(|| Game::new(select_word(req)));

    if game.outcome() != Outcome::InProgress {
        *game = Game::new(select_word(req));
    }

    Ok(create_response(&game.check()))
}

pub fn guess(req: &mut Request) -> IronResult<Response> {
    let token = req.token()?.to_owned();
    let guess = req.guess()?;
    let mutex = req.get::<Write<GameStore>>().expect("gamestore not found");

    let mut games = mutex.lock().expect("unable to lock mutex");
    let mut game = games.entry(token).or_insert_with(|| Game::new(select_word(req)));

    if game.outcome() != Outcome::InProgress {
        *game = Game::new(select_word(req));
    }

    Ok(create_response(&game.guess(&guess)))
}

fn create_response<T: Serialize>(model: &T) -> Response {
    use iron::headers::ContentType;

    let mut response = Response::with((
        status::Ok,
        serialize(model).unwrap(),
    ));
    response.headers.set(ContentType::json());
    response
}

fn select_word(req: &mut Request) -> String {
    use rand::{Rng, thread_rng};
    use words::WordList;

    let word_list = req.get::<Read<WordList>>().expect("wordlist not found");
    thread_rng().choose(&word_list).map_or("apple".to_owned(), |word| word.to_owned())
}<|endoftext|>


<commit_before>extern crate kafka;
extern crate getopts;
extern crate env_logger;

use std::{env, fmt, process};
use std::io::{self, Write};
use std::ascii::AsciiExt;

use kafka::consumer::{Consumer, GroupOffsetStorage};

/// This is a very simple command line application reading from a
/// specific kafka topic and dumping the messages to standard output.
fn main() {
    env_logger::init().unwrap();

    let cfg = match Config::from_cmdline() {
        Ok(cfg) => cfg,
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
    };
    if let Err(e) = process(cfg) {
        println!("{}", e);
        process::exit(1);
    }
}

fn process(cfg: Config) -> Result<(), Error> {
    let mut c = {
        let mut cb = Consumer::from_hosts(cfg.brokers)
            .with_group(cfg.group)
            .with_fetch_max_wait_time(1000)
            .with_fetch_min_bytes(1_000)
            .with_fetch_max_bytes_per_partition(100_000)
            .with_retry_max_bytes_limit(1_000_000)
            .with_offset_storage(cfg.offset_storage);
        for topic in cfg.topics {
            cb = cb.with_topic(topic);
        }
        try!(cb.create())
    };

    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut buf = Vec::with_capacity(1024);

    let do_commit = !cfg.no_commit;
    loop {
        for ms in try!(c.poll()).iter() {
            for m in ms.messages() {
                // ~ clear the output buffer
                unsafe { buf.set_len(0) };
                // ~ format the message for output
                let _ = write!(buf, "{}:{}@{}:\n", ms.topic(), ms.partition(), m.offset);
                buf.extend_from_slice(m.value);
                buf.push(b'\n');
                // ~ write to output channel
                try!(stdout.write_all(&buf));
            }
            let _ = c.consume_messageset(ms);
        }
        if do_commit {
            try!(c.commit_consumed());
        }
    }
}

// --------------------------------------------------------------------

enum Error {
    Kafka(kafka::error::Error),
    Io(io::Error),
    Literal(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Kafka(ref e) => write!(f, "kafka-error: {}", e),
            &Error::Io(ref e) => write!(f, "io-error: {}", e),
            &Error::Literal(ref s) => write!(f, "{}", s),
        }
    }
}

impl From<kafka::error::Error> for Error {
    fn from(e: kafka::error::Error) -> Self { Error::Kafka(e) }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self { Error::Io(e) }
}

// --------------------------------------------------------------------

struct Config {
    brokers: Vec<String>,
    group: String,
    topics: Vec<String>,
    no_commit: bool,
    offset_storage: GroupOffsetStorage,
}

impl Config {
    fn from_cmdline() -> Result<Config, Error> {
        let args: Vec<_> = env::args().collect();
        let mut opts = getopts::Options::new();
        opts.optflag("h", "help", "Print this help screen");
        opts.optopt("", "brokers", "Specify kafka brokers (comma separated)", "HOSTS");
        opts.optopt("", "topics", "Specify topics (comma separated)", "NAMES");
        opts.optopt("", "group", "Specify the consumer group", "NAME");
        opts.optflag("", "no-commit", "Do not commit consumed messages");
        opts.optopt("", "offsets", "Specify the offset store [zookeeper, kafka]", "STORE");

        let m = match opts.parse(&args[1..]) {
            Ok(m) => m,
            Err(e) => return Err(Error::Literal(e.to_string())),
        };
        if m.opt_present("help") {
            let brief = format!("{} [options]", args[0]);
            return Err(Error::Literal(opts.usage(&brief)));
        }

        macro_rules! required_list {
            ($name:expr) => {{
                let opt = $name;
                let xs: Vec<_> = match m.opt_str(opt) {
                    None => return Err(Error::Literal(format!("Required option --{} missing", opt))),
                    Some(s) => s.split(',').map(|s| s.trim().to_owned()).filter(|s| !s.is_empty()).collect(),
                };
                if xs.is_empty() {
                    return Err(Error::Literal(format!("Invalid --{} specified!", opt)));
                }
                xs
            }}
        };

        let brokers = required_list!("brokers");
        let topics = required_list!("topics");

        let mut offset_storage = GroupOffsetStorage::Zookeeper;
        if let Some(s) = m.opt_str("offsets") {
            if s.eq_ignore_ascii_case("zookeeper") {
                offset_storage = GroupOffsetStorage::Zookeeper;
            } else if s.eq_ignore_ascii_case("kafka") {
                offset_storage = GroupOffsetStorage::Kafka;
            } else {
                return Err(Error::Literal(format!("unknown offset store: {}", s)));
            }
        }
        Ok(Config {
            brokers: brokers,
            group: m.opt_str("group").unwrap_or_else(|| String::new()),
            topics: topics,
            no_commit: m.opt_present("no-commit"),
            offset_storage: offset_storage,
        })
   }
}
<commit_msg>console-cosumer: allowing specifying fallback offset<commit_after>extern crate kafka;
extern crate getopts;
extern crate env_logger;

use std::{env, fmt, process};
use std::io::{self, Write};
use std::ascii::AsciiExt;

use kafka::consumer::{Consumer, FetchOffset, GroupOffsetStorage};

/// This is a very simple command line application reading from a
/// specific kafka topic and dumping the messages to standard output.
fn main() {
    env_logger::init().unwrap();

    let cfg = match Config::from_cmdline() {
        Ok(cfg) => cfg,
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
    };
    if let Err(e) = process(cfg) {
        println!("{}", e);
        process::exit(1);
    }
}

fn process(cfg: Config) -> Result<(), Error> {
    let mut c = {
        let mut cb = Consumer::from_hosts(cfg.brokers)
            .with_group(cfg.group)
            .with_fallback_offset(cfg.fallback_offset)
            .with_fetch_max_wait_time(1000)
            .with_fetch_min_bytes(1_000)
            .with_fetch_max_bytes_per_partition(100_000)
            .with_retry_max_bytes_limit(1_000_000)
            .with_offset_storage(cfg.offset_storage);
        for topic in cfg.topics {
            cb = cb.with_topic(topic);
        }
        try!(cb.create())
    };

    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut buf = Vec::with_capacity(1024);

    let do_commit = !cfg.no_commit;
    loop {
        for ms in try!(c.poll()).iter() {
            for m in ms.messages() {
                // ~ clear the output buffer
                unsafe { buf.set_len(0) };
                // ~ format the message for output
                let _ = write!(buf, "{}:{}@{}:\n", ms.topic(), ms.partition(), m.offset);
                buf.extend_from_slice(m.value);
                buf.push(b'\n');
                // ~ write to output channel
                try!(stdout.write_all(&buf));
            }
            let _ = c.consume_messageset(ms);
        }
        if do_commit {
            try!(c.commit_consumed());
        }
    }
}

// --------------------------------------------------------------------

enum Error {
    Kafka(kafka::error::Error),
    Io(io::Error),
    Literal(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Kafka(ref e) => write!(f, "kafka-error: {}", e),
            &Error::Io(ref e) => write!(f, "io-error: {}", e),
            &Error::Literal(ref s) => write!(f, "{}", s),
        }
    }
}

impl From<kafka::error::Error> for Error {
    fn from(e: kafka::error::Error) -> Self { Error::Kafka(e) }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self { Error::Io(e) }
}

// --------------------------------------------------------------------

struct Config {
    brokers: Vec<String>,
    group: String,
    topics: Vec<String>,
    no_commit: bool,
    offset_storage: GroupOffsetStorage,
    fallback_offset: FetchOffset,
}

impl Config {
    fn from_cmdline() -> Result<Config, Error> {
        let args: Vec<_> = env::args().collect();
        let mut opts = getopts::Options::new();
        opts.optflag("h", "help", "Print this help screen");
        opts.optopt("", "brokers", "Specify kafka brokers (comma separated)", "HOSTS");
        opts.optopt("", "topics", "Specify topics (comma separated)", "NAMES");
        opts.optopt("", "group", "Specify the consumer group", "NAME");
        opts.optflag("", "no-commit", "Do not commit consumed messages");
        opts.optopt("", "offsets", "Specify the offset store [zookeeper, kafka]", "STORE");
        opts.optflag("", "earliest", "Fall back to the earliest offset");

        let m = match opts.parse(&args[1..]) {
            Ok(m) => m,
            Err(e) => return Err(Error::Literal(e.to_string())),
        };
        if m.opt_present("help") {
            let brief = format!("{} [options]", args[0]);
            return Err(Error::Literal(opts.usage(&brief)));
        }

        macro_rules! required_list {
            ($name:expr) => {{
                let opt = $name;
                let xs: Vec<_> = match m.opt_str(opt) {
                    None => return Err(Error::Literal(format!("Required option --{} missing", opt))),
                    Some(s) => s.split(',').map(|s| s.trim().to_owned()).filter(|s| !s.is_empty()).collect(),
                };
                if xs.is_empty() {
                    return Err(Error::Literal(format!("Invalid --{} specified!", opt)));
                }
                xs
            }}
        };

        let brokers = required_list!("brokers");
        let topics = required_list!("topics");

        let mut offset_storage = GroupOffsetStorage::Zookeeper;
        if let Some(s) = m.opt_str("offsets") {
            if s.eq_ignore_ascii_case("zookeeper") {
                offset_storage = GroupOffsetStorage::Zookeeper;
            } else if s.eq_ignore_ascii_case("kafka") {
                offset_storage = GroupOffsetStorage::Kafka;
            } else {
                return Err(Error::Literal(format!("unknown offset store: {}", s)));
            }
        }
        Ok(Config {
            brokers: brokers,
            group: m.opt_str("group").unwrap_or_else(|| String::new()),
            topics: topics,
            no_commit: m.opt_present("no-commit"),
            offset_storage: offset_storage,
            fallback_offset: if m.opt_present("earliest") {
                FetchOffset::Earliest
            } else {
                FetchOffset::Latest
            },
        })
   }
}
<|endoftext|>