<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Utilities for working with packets, eg. checksumming.

use ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::u8;
use std::u16;
use std::convert::TryInto;

/// Convert a value to a byte array.
pub trait Octets {
    /// Output type - bytes array.
    type Output;

    /// Return a value as bytes (big-endian order).
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    if data.len() == 0 { return 0 }
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by UDP and TCP.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv4Addr,
                     destination: &Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: &Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6.
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv6Addr,
                     destination: &Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: &Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: usize) -> u32 {
    if data.len() == 0 { return 0 }
    let len = data.len();
    let mut cur_data = &data[..];
    let mut sum = 0u32;
    let mut i = 0;
    while cur_data.len() >= 2 {
        if i != skipword {
            // It's safe to unwrap because we verified there are at least 2 bytes
            sum += u16::from_be_bytes(cur_data[0..2].try_into().unwrap()) as u32;
        }
        cur_data = &cur_data[2..];
        i += 1;
    }

    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

#[cfg(test)]
mod tests {
    use super::sum_be_words;
    use std::slice;

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }

    #[test]
    fn sum_be_words_misaligned_ptr() {
        let mut data = vec![0; 13];
        let ptr = match data.as_ptr() as usize % 2 {
            0 => {
                unsafe { data.as_mut_ptr().offset(1) }
            }
            _ => data.as_mut_ptr(),
        };
        unsafe {
            let slice_data = slice::from_raw_parts_mut(ptr, 12);
            for i in 0..11 {
                slice_data[i] = i as u8;
            }
            assert_eq!(7190, sum_be_words(&slice_data, 1));
            assert_eq!(6676, sum_be_words(&slice_data, 2));
            // Assert having the skipword outside the range gives correct and equal
            // results
            assert_eq!(7705, sum_be_words(&slice_data, 99));
            assert_eq!(7705, sum_be_words(&slice_data, 101));
        }
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}

<commit_msg>Add additional unit tests for small buffer edge cases.<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Utilities for working with packets, eg. checksumming.

use ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::u8;
use std::u16;
use std::convert::TryInto;

/// Convert a value to a byte array.
pub trait Octets {
    /// Output type - bytes array.
    type Output;

    /// Return a value as bytes (big-endian order).
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    if data.len() == 0 { return 0 }
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by UDP and TCP.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv4Addr,
                     destination: &Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: &Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6.
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv6Addr,
                     destination: &Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: &Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: usize) -> u32 {
    if data.len() == 0 { return 0 }
    let len = data.len();
    let mut cur_data = &data[..];
    let mut sum = 0u32;
    let mut i = 0;
    while cur_data.len() >= 2 {
        if i != skipword {
            // It's safe to unwrap because we verified there are at least 2 bytes
            sum += u16::from_be_bytes(cur_data[0..2].try_into().unwrap()) as u32;
        }
        cur_data = &cur_data[2..];
        i += 1;
    }

    // If the length is odd, make sure to checksum the final byte
    if i != skipword && len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

#[cfg(test)]
mod tests {
    use super::sum_be_words;
    use std::slice;

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }

    #[test]
    fn sum_be_words_small_sizes() {
        let data_zero = vec![0; 0];
        assert_eq!(0, sum_be_words(&data_zero, 0));
        assert_eq!(0, sum_be_words(&data_zero, 10));
        let data_one = vec![1; 1];
        assert_eq!(0, sum_be_words(&data_zero, 0));
        assert_eq!(256, sum_be_words(&data_one, 1));
        let data_two = vec![1; 2];
        assert_eq!(0, sum_be_words(&data_two, 0));
        assert_eq!(257, sum_be_words(&data_two, 1));
        let data_three = vec![4; 3];
        assert_eq!(1024, sum_be_words(&data_three, 0));
        assert_eq!(1028, sum_be_words(&data_three, 1));
        assert_eq!(2052, sum_be_words(&data_three, 2));
        assert_eq!(2052, sum_be_words(&data_three, 3));
    }

    #[test]
    fn sum_be_words_misaligned_ptr() {
        let mut data = vec![0; 13];
        let ptr = match data.as_ptr() as usize % 2 {
            0 => {
                unsafe { data.as_mut_ptr().offset(1) }
            }
            _ => data.as_mut_ptr(),
        };
        unsafe {
            let slice_data = slice::from_raw_parts_mut(ptr, 12);
            for i in 0..11 {
                slice_data[i] = i as u8;
            }
            assert_eq!(7190, sum_be_words(&slice_data, 1));
            assert_eq!(6676, sum_be_words(&slice_data, 2));
            // Assert having the skipword outside the range gives correct and equal
            // results
            assert_eq!(7705, sum_be_words(&slice_data, 99));
            assert_eq!(7705, sum_be_words(&slice_data, 101));
        }
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}

<|endoftext|>


<commit_before>// ignore-tidy-linelength
// aux-build:unstable_generic_param.rs

extern crate unstable_generic_param;

use unstable_generic_param::*;

struct R;

impl Trait1 for S {
    fn foo() -> () { () } // ok
}

struct S;

impl Trait1<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
    fn foo() -> usize { 0 }
}

impl Trait1<isize> for S { //~ ERROR use of unstable library feature 'unstable_default'
    fn foo() -> isize { 0 }
}

impl Trait2<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
    fn foo() -> usize { 0 }
}

impl Trait3<usize> for S {
    fn foo() -> usize { 0 } // ok
}

fn main() {
    let _ = S;

    let _ = Struct1 { field: 1 }; // ERROR use of unstable library feature 'unstable_default'
    let _: Struct1 = Struct1 { field: 1 }; // ERROR use of unstable library feature 'unstable_default'
    let _: Struct1<isize> = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'

    let _ = STRUCT1; // ok
    let _: Struct1 = STRUCT1; // ok
    let _: Struct1<usize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'
    let _: Struct1<usize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'
    let _ = STRUCT1.field; // ok
    let _: usize = STRUCT1.field; // ERROR use of unstable library feature 'unstable_default'
    let _ = STRUCT1.field + 1; // ERROR use of unstable library feature 'unstable_default'
    let _ = STRUCT1.field + 1usize; // ERROR use of unstable library feature 'unstable_default'

    let _ = Struct2 { field: 1 }; // ok
    let _: Struct2 = Struct2 { field: 1 }; // ok
    let _: Struct2<usize> = Struct2 { field: 1 }; // ok

    let _ = STRUCT2;
    let _: Struct2 = STRUCT2; // ok
    let _: Struct2<usize> = STRUCT2; // ok
    let _: Struct2<usize> = STRUCT2; // ok
    let _ = STRUCT2.field; // ok
    let _: usize = STRUCT2.field; // ok
    let _ = STRUCT2.field + 1; // ok
    let _ = STRUCT2.field + 1usize; // ok
}
<commit_msg>Unstable default types leak in public fields<commit_after>// ignore-tidy-linelength
// aux-build:unstable_generic_param.rs

extern crate unstable_generic_param;

use unstable_generic_param::*;

struct R;

impl Trait1 for S {
    fn foo() -> () { () } // ok
}

struct S;

impl Trait1<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
    fn foo() -> usize { 0 }
}

impl Trait1<isize> for S { //~ ERROR use of unstable library feature 'unstable_default'
    fn foo() -> isize { 0 }
}

impl Trait2<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
    fn foo() -> usize { 0 }
}

impl Trait3<usize> for S {
    fn foo() -> usize { 0 } // ok
}

fn main() {
    let _ = S;

    let _: Struct1<isize> = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'

    let _ = STRUCT1; // ok
    let _: Struct1 = STRUCT1; // ok
    let _: Struct1<usize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'
    let _: Struct1<isize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'

    // Instability is not enforced for generic type parameters used in public fields.
    // Note how the unstable type default `usize` leaks,
    // and can be used without the 'unstable_default' feature.
    let _ = STRUCT1.field;
    let _ = Struct1 { field: 1 };
    let _: Struct1 = Struct1 { field: 1 };
    let _: usize = STRUCT1.field;
    let _ = STRUCT1.field + 1;
    let _ = STRUCT1.field + 1usize;

    let _ = Struct2 { field: 1 }; // ok
    let _: Struct2 = Struct2 { field: 1 }; // ok
    let _: Struct2<usize> = Struct2 { field: 1 }; // ok

    let _ = STRUCT2;
    let _: Struct2 = STRUCT2; // ok
    let _: Struct2<usize> = STRUCT2; // ok
    let _: Struct2<usize> = STRUCT2; // ok
    let _ = STRUCT2.field; // ok
    let _: usize = STRUCT2.field; // ok
    let _ = STRUCT2.field + 1; // ok
    let _ = STRUCT2.field + 1usize; // ok
}
<|endoftext|>


<commit_before>// Copyright 2015 Jan Likar.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

use anyhow::{bail, Context};

use cargo::core::dependency::Dependency;
use cargo::core::source::{Source, SourceId};
use cargo::core::Package;
use cargo::sources::{PathSource, SourceConfigMap};
use cargo::util::{CargoResult, Config};

use semver::VersionReq;

use walkdir::WalkDir;

#[derive(PartialEq, Eq, Debug)]
pub struct Crate {
    name: String,
    version: Option<String>,
}

impl Crate {
    pub fn new(name: String, version: Option<String>) -> Crate {
        Crate { name, version }
    }
}

pub struct CloneOpts<'a> {
    crates: &'a [Crate],
    srcid: &'a SourceId,
    directory: Option<&'a str>,
    git: bool,
}

impl<'a> CloneOpts<'a> {
    pub fn new(
        crates: &'a [Crate],
        srcid: &'a SourceId,
        directory: Option<&'a str>,
        git: bool,
    ) -> CloneOpts<'a> {
        CloneOpts {
            crates,
            srcid,
            directory,
            git,
        }
    }
}

/// Clone the specified crate from registry or git repository.
pub fn clone(opts: &CloneOpts, config: &Config) -> CargoResult<()> {
    let _lock = config.acquire_package_cache_lock()?;

    let multiple_crates = opts.crates.len() > 1;
    let can_clone_in_dir = opts.directory.map(|d| d.ends_with('/')).unwrap_or(true);
    let should_append_crate_dir = multiple_crates || can_clone_in_dir;

    // If prefix was not supplied, use current dir.
    let dir_path = opts
        .directory
        .map(PathBuf::from)
        .unwrap_or(env::current_dir()?);

    for crate_ in opts.crates {
        let mut dest_path = dir_path.clone();

        if should_append_crate_dir {
            dest_path.push(&crate_.name);
        }

        if !dest_path.exists() {
            fs::create_dir_all(&dest_path)?;
        }

        config
            .shell()
            .verbose(|s| s.note(format!("Cloning into {:?}", &dir_path)))?;

        // Cloning into an existing directory is only allowed if the directory is empty.
        let is_empty = dest_path.read_dir()?.next().is_none();
        if !is_empty {
            bail!(
                "destination path '{}' already exists and is not an empty directory.",
                dest_path.display()
            );
        }

        clone_single(crate_, &dest_path, opts, config)?;
    }

    Ok(())
}

pub fn clone_single(
    crate_: &Crate,
    dest_path: &Path,
    opts: &CloneOpts,
    config: &Config,
) -> CargoResult<()> {
    let pkg = get_package(crate_, opts, config)?;

    if opts.git {
        let repo = &pkg.manifest().metadata().repository;

        if repo.is_none() {
            bail!(
                "Cannot clone {} from git repo because it is not specified in package's manifest.",
                &crate_.name
            )
        }

        clone_git_repo(repo.as_ref().unwrap(), dest_path)?;
    } else {
        clone_directory(pkg.root(), dest_path)?;
    }

    Ok(())
}

fn get_package(crate_: &Crate, opts: &CloneOpts, config: &Config) -> CargoResult<Package> {
    if opts.srcid.is_path() {
        let path = opts.srcid.url().to_file_path().expect("path must be valid");
        let src = PathSource::new(&path, *opts.srcid, config);

        select_pkg(config, src, &crate_.name, crate_.version.as_deref())
    } else {
        let map = SourceConfigMap::new(config)?;
        select_pkg(
            config,
            map.load(*opts.srcid, &Default::default())?,
            &crate_.name,
            crate_.version.as_deref(),
        )
    }
}

fn select_pkg<'a, T>(
    config: &Config,
    mut src: T,
    name: &str,
    vers: Option<&str>,
) -> CargoResult<Package>
where
    T: Source + 'a,
{
    src.update()?;

    let dep = Dependency::parse(name, vers, src.source_id())?;
    let mut summaries = vec![];
    src.query(&dep, &mut |summary| summaries.push(summary))?;

    let latest = summaries.iter().max_by_key(|s| s.version());

    match latest {
        Some(l) => {
            config
                .shell()
                .note(format!("Downloading {} {}", name, l.version()))?;
            let pkg = Box::new(src).download_now(l.package_id(), config)?;
            Ok(pkg)
        }
        None => bail!("Package `{}@{}` not found", name, vers.unwrap_or("*.*.*")),
    }
}

fn parse_version_req(version: &str) -> CargoResult<String> {
    // This function's main purpose is to treat "x.y.z" as "=x.y.z"
    // so specifying the version in CLI works as expected.
    let first = version.chars().next();

    if first.is_none() {
        bail!("Version cannot be empty.")
    };

    let is_req = "<>=^~".contains(first.unwrap()) || version.contains('*');

    if is_req {
        let vers = VersionReq::parse(version)
            .with_context(|| format!("Invalid version requirement: `{}`.", version))?;
        Ok(vers.to_string())
    } else {
        Ok(format!("={}", version))
    }
}

// clone_directory copies the contents of one directory into another directory, which must
// already exist.
fn clone_directory(from: &Path, to: &Path) -> CargoResult<()> {
    if !to.is_dir() {
        bail!("Not a directory: {}", to.to_string_lossy());
    }
    for entry in WalkDir::new(from) {
        let entry = entry.unwrap();
        let file_type = entry.file_type();
        let mut dest_path = to.to_owned();
        dest_path.push(entry.path().strip_prefix(from).unwrap());

        if entry.file_name() == ".cargo-ok" {
            continue;
        }

        if file_type.is_file() {
            // .cargo-ok is not wanted in this context
            fs::copy(&entry.path(), &dest_path)?;
        } else if file_type.is_dir() {
            if dest_path == to {
                continue;
            }
            fs::create_dir(&dest_path)?;
        }
    }

    Ok(())
}

fn clone_git_repo(repo: &str, to: &Path) -> CargoResult<()> {
    let status = Command::new("git")
        .arg("clone")
        .arg(repo)
        .arg(to.to_str().unwrap())
        .status()
        .context("Failed to clone from git repo.")?;

    if !status.success() {
        bail!("Failed to clone from git repo.")
    }

    Ok(())
}

/// Parses crate specifications like: crate, crate@x.y.z, crate@~23.4.5.
pub fn parse_name_and_version(spec: &str) -> CargoResult<Crate> {
    if !spec.contains('@') {
        return Ok(Crate::new(spec.to_owned(), None));
    }

    let mut parts = spec.split('@');
    let crate_ = parts
        .next()
        .context(format!("Crate name missing in `{}`.", spec))?;
    let version = parts
        .next()
        .context(format!("Crate version missing in `{}`.", spec))?;

    Ok(Crate::new(
        crate_.to_owned(),
        Some(parse_version_req(version)?),
    ))
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_parse_version_req() {
        assert_eq!("=12.4.5", parse_version_req("12.4.5").unwrap());
        assert_eq!("=12.4.5", parse_version_req("=12.4.5").unwrap());
        assert_eq!("12.2.*", parse_version_req("12.2.*").unwrap());
    }

    #[test]
    fn test_parse_version_req_invalid_req() {
        assert_eq!(
            "Invalid version requirement: `=foo`.",
            parse_version_req("=foo").unwrap_err().to_string()
        );
    }

    #[test]
    fn test_clone_directory() {
        let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
        let from = PathBuf::from(manifest_dir).join("tests/data");
        let to = TempDir::new("cargo-clone-tests").unwrap();
        let to_path = to.path();

        clone_directory(&from, to_path).unwrap();

        assert!(to_path.join("Cargo.toml").exists());
        assert!(!to_path.join("cargo-ok").exists());
    }

    #[test]
    fn test_clone_repo() {
        let to = TempDir::new("cargo-clone-tests").unwrap();
        let to_path = to.path();

        clone_git_repo("https://github.com/janlikar/cargo-clone", to_path).unwrap();

        assert!(to_path.exists());
        assert!(to_path.join(".git").exists());
    }

    #[test]
    fn test_parse_name_and_version() {
        assert_eq!(
            parse_name_and_version("foo").unwrap(),
            Crate::new(String::from("foo"), None)
        );
        assert_eq!(
            parse_name_and_version("foo@1.1.3").unwrap(),
            Crate::new(String::from("foo"), Some(String::from("=1.1.3")))
        );
        assert_eq!(
            parse_name_and_version("foo@~1.1.3").unwrap(),
            Crate::new(String::from("foo"), Some(String::from("~1.1.3")))
        );
        assert_eq!(
            parse_name_and_version("foo@1.1.*").unwrap(),
            Crate::new(String::from("foo"), Some(String::from("1.1.*")))
        );
    }
}
<commit_msg>feat: re-export cargo types (#52)<commit_after>// Copyright 2015 Jan Likar.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

use anyhow::{bail, Context};

use cargo::core::dependency::Dependency;
use cargo::core::source::Source;
use cargo::core::Package;
use cargo::sources::{PathSource, SourceConfigMap};

use semver::VersionReq;

use walkdir::WalkDir;

// Re-export cargo types.
pub use cargo::{
    core::SourceId,
    util::{CargoResult, Config},
};

#[derive(PartialEq, Eq, Debug)]
pub struct Crate {
    name: String,
    version: Option<String>,
}

impl Crate {
    pub fn new(name: String, version: Option<String>) -> Crate {
        Crate { name, version }
    }
}

pub struct CloneOpts<'a> {
    crates: &'a [Crate],
    srcid: &'a SourceId,
    directory: Option<&'a str>,
    git: bool,
}

impl<'a> CloneOpts<'a> {
    pub fn new(
        crates: &'a [Crate],
        srcid: &'a SourceId,
        directory: Option<&'a str>,
        git: bool,
    ) -> CloneOpts<'a> {
        CloneOpts {
            crates,
            srcid,
            directory,
            git,
        }
    }
}

/// Clone the specified crate from registry or git repository.
pub fn clone(opts: &CloneOpts, config: &Config) -> CargoResult<()> {
    let _lock = config.acquire_package_cache_lock()?;

    let multiple_crates = opts.crates.len() > 1;
    let can_clone_in_dir = opts.directory.map(|d| d.ends_with('/')).unwrap_or(true);
    let should_append_crate_dir = multiple_crates || can_clone_in_dir;

    // If prefix was not supplied, use current dir.
    let dir_path = opts
        .directory
        .map(PathBuf::from)
        .unwrap_or(env::current_dir()?);

    for crate_ in opts.crates {
        let mut dest_path = dir_path.clone();

        if should_append_crate_dir {
            dest_path.push(&crate_.name);
        }

        if !dest_path.exists() {
            fs::create_dir_all(&dest_path)?;
        }

        config
            .shell()
            .verbose(|s| s.note(format!("Cloning into {:?}", &dir_path)))?;

        // Cloning into an existing directory is only allowed if the directory is empty.
        let is_empty = dest_path.read_dir()?.next().is_none();
        if !is_empty {
            bail!(
                "destination path '{}' already exists and is not an empty directory.",
                dest_path.display()
            );
        }

        clone_single(crate_, &dest_path, opts, config)?;
    }

    Ok(())
}

pub fn clone_single(
    crate_: &Crate,
    dest_path: &Path,
    opts: &CloneOpts,
    config: &Config,
) -> CargoResult<()> {
    let pkg = get_package(crate_, opts, config)?;

    if opts.git {
        let repo = &pkg.manifest().metadata().repository;

        if repo.is_none() {
            bail!(
                "Cannot clone {} from git repo because it is not specified in package's manifest.",
                &crate_.name
            )
        }

        clone_git_repo(repo.as_ref().unwrap(), dest_path)?;
    } else {
        clone_directory(pkg.root(), dest_path)?;
    }

    Ok(())
}

fn get_package(crate_: &Crate, opts: &CloneOpts, config: &Config) -> CargoResult<Package> {
    if opts.srcid.is_path() {
        let path = opts.srcid.url().to_file_path().expect("path must be valid");
        let src = PathSource::new(&path, *opts.srcid, config);

        select_pkg(config, src, &crate_.name, crate_.version.as_deref())
    } else {
        let map = SourceConfigMap::new(config)?;
        select_pkg(
            config,
            map.load(*opts.srcid, &Default::default())?,
            &crate_.name,
            crate_.version.as_deref(),
        )
    }
}

fn select_pkg<'a, T>(
    config: &Config,
    mut src: T,
    name: &str,
    vers: Option<&str>,
) -> CargoResult<Package>
where
    T: Source + 'a,
{
    src.update()?;

    let dep = Dependency::parse(name, vers, src.source_id())?;
    let mut summaries = vec![];
    src.query(&dep, &mut |summary| summaries.push(summary))?;

    let latest = summaries.iter().max_by_key(|s| s.version());

    match latest {
        Some(l) => {
            config
                .shell()
                .note(format!("Downloading {} {}", name, l.version()))?;
            let pkg = Box::new(src).download_now(l.package_id(), config)?;
            Ok(pkg)
        }
        None => bail!("Package `{}@{}` not found", name, vers.unwrap_or("*.*.*")),
    }
}

fn parse_version_req(version: &str) -> CargoResult<String> {
    // This function's main purpose is to treat "x.y.z" as "=x.y.z"
    // so specifying the version in CLI works as expected.
    let first = version.chars().next();

    if first.is_none() {
        bail!("Version cannot be empty.")
    };

    let is_req = "<>=^~".contains(first.unwrap()) || version.contains('*');

    if is_req {
        let vers = VersionReq::parse(version)
            .with_context(|| format!("Invalid version requirement: `{}`.", version))?;
        Ok(vers.to_string())
    } else {
        Ok(format!("={}", version))
    }
}

// clone_directory copies the contents of one directory into another directory, which must
// already exist.
fn clone_directory(from: &Path, to: &Path) -> CargoResult<()> {
    if !to.is_dir() {
        bail!("Not a directory: {}", to.to_string_lossy());
    }
    for entry in WalkDir::new(from) {
        let entry = entry.unwrap();
        let file_type = entry.file_type();
        let mut dest_path = to.to_owned();
        dest_path.push(entry.path().strip_prefix(from).unwrap());

        if entry.file_name() == ".cargo-ok" {
            continue;
        }

        if file_type.is_file() {
            // .cargo-ok is not wanted in this context
            fs::copy(&entry.path(), &dest_path)?;
        } else if file_type.is_dir() {
            if dest_path == to {
                continue;
            }
            fs::create_dir(&dest_path)?;
        }
    }

    Ok(())
}

fn clone_git_repo(repo: &str, to: &Path) -> CargoResult<()> {
    let status = Command::new("git")
        .arg("clone")
        .arg(repo)
        .arg(to.to_str().unwrap())
        .status()
        .context("Failed to clone from git repo.")?;

    if !status.success() {
        bail!("Failed to clone from git repo.")
    }

    Ok(())
}

/// Parses crate specifications like: crate, crate@x.y.z, crate@~23.4.5.
pub fn parse_name_and_version(spec: &str) -> CargoResult<Crate> {
    if !spec.contains('@') {
        return Ok(Crate::new(spec.to_owned(), None));
    }

    let mut parts = spec.split('@');
    let crate_ = parts
        .next()
        .context(format!("Crate name missing in `{}`.", spec))?;
    let version = parts
        .next()
        .context(format!("Crate version missing in `{}`.", spec))?;

    Ok(Crate::new(
        crate_.to_owned(),
        Some(parse_version_req(version)?),
    ))
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_parse_version_req() {
        assert_eq!("=12.4.5", parse_version_req("12.4.5").unwrap());
        assert_eq!("=12.4.5", parse_version_req("=12.4.5").unwrap());
        assert_eq!("12.2.*", parse_version_req("12.2.*").unwrap());
    }

    #[test]
    fn test_parse_version_req_invalid_req() {
        assert_eq!(
            "Invalid version requirement: `=foo`.",
            parse_version_req("=foo").unwrap_err().to_string()
        );
    }

    #[test]
    fn test_clone_directory() {
        let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
        let from = PathBuf::from(manifest_dir).join("tests/data");
        let to = TempDir::new("cargo-clone-tests").unwrap();
        let to_path = to.path();

        clone_directory(&from, to_path).unwrap();

        assert!(to_path.join("Cargo.toml").exists());
        assert!(!to_path.join("cargo-ok").exists());
    }

    #[test]
    fn test_clone_repo() {
        let to = TempDir::new("cargo-clone-tests").unwrap();
        let to_path = to.path();

        clone_git_repo("https://github.com/janlikar/cargo-clone", to_path).unwrap();

        assert!(to_path.exists());
        assert!(to_path.join(".git").exists());
    }

    #[test]
    fn test_parse_name_and_version() {
        assert_eq!(
            parse_name_and_version("foo").unwrap(),
            Crate::new(String::from("foo"), None)
        );
        assert_eq!(
            parse_name_and_version("foo@1.1.3").unwrap(),
            Crate::new(String::from("foo"), Some(String::from("=1.1.3")))
        );
        assert_eq!(
            parse_name_and_version("foo@~1.1.3").unwrap(),
            Crate::new(String::from("foo"), Some(String::from("~1.1.3")))
        );
        assert_eq!(
            parse_name_and_version("foo@1.1.*").unwrap(),
            Crate::new(String::from("foo"), Some(String::from("1.1.*")))
        );
    }
}
<|endoftext|>


<commit_before>//! Highly optimised prime sieves.
//!
//! This is designed to be used via the `primal` crate.

#![cfg_attr(feature = "unstable", feature(llvm_asm))]

// black boxes for pointers; LLVM isn't so happy without
// them. Unfortunately only usable with unstable, but the code isn't
// *too* much slower without them.
#[cfg(feature = "unstable")]
#[inline(always)]
fn b<T>(mut p: *mut T) -> *mut T { unsafe { llvm_asm!("": "+r"(p)) } p }
#[cfg(not(feature = "unstable"))]
#[inline(always)]
fn b<T>(p: *mut T) -> *mut T { p }

#[cfg(feature = "safe")]
macro_rules! safe_assert {
    ($x: expr) => {
        assert!($x);
    }
}
#[cfg(not(feature = "safe"))]
macro_rules! safe_assert {
    ($x: expr) => { () }
}

mod streaming;
pub use crate::streaming::StreamingSieve;
pub use crate::streaming::primes::Primes;

// mod wheel6;
mod wheel;
mod sieve;

pub use crate::sieve::{Sieve, SievePrimes};
<commit_msg>Use the new asm! in the unstable primal_sieve::b<commit_after>//! Highly optimised prime sieves.
//!
//! This is designed to be used via the `primal` crate.

// black boxes for pointers; LLVM isn't so happy without
// them. Unfortunately only usable with 1.59+ asm!, but the code isn't
// *too* much slower without them.
#[cfg(feature = "unstable")]
#[inline(always)]
fn b<T>(mut p: *mut T) -> *mut T { unsafe { core::arch::asm!("/* {0} */", inout(reg) p) } p }
#[cfg(not(feature = "unstable"))]
#[inline(always)]
fn b<T>(p: *mut T) -> *mut T { p }

#[cfg(feature = "safe")]
macro_rules! safe_assert {
    ($x: expr) => {
        assert!($x);
    }
}
#[cfg(not(feature = "safe"))]
macro_rules! safe_assert {
    ($x: expr) => { () }
}

mod streaming;
pub use crate::streaming::StreamingSieve;
pub use crate::streaming::primes::Primes;

// mod wheel6;
mod wheel;
mod sieve;

pub use crate::sieve::{Sieve, SievePrimes};
<|endoftext|>


<commit_before>//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS
//! CRATE**.

bitflags! {
    /// This is the same `Flags` struct defined in the [crate level example](../index.html#example).
    /// Note that this struct is just for documentation purposes only, it must not be used outside
    /// this crate.
    pub struct Flags: u32 {
        const FLAG_A = 0b00000001;
        const FLAG_B = 0b00000010;
        const FLAG_C = 0b00000100;
        const FLAG_ABC = Self::FLAG_A.bits | Self::FLAG_B.bits | Self::FLAG_C.bits;
    }
}
<commit_msg>Fix the example `Flags` struct<commit_after>//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS
//! CRATE**.

bitflags! {
    /// This is the same `Flags` struct defined in the [crate level example](../index.html#example).
    /// Note that this struct is just for documentation purposes only, it must not be used outside
    /// this crate.
    struct Flags: u32 {
        const A = 0b00000001;
        const B = 0b00000010;
        const C = 0b00000100;
        const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
    }
}
<|endoftext|>


<commit_before>use libc::{c_uint, c_int};
use std::{ffi, str, mem, ptr};
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher, Writer};

pub mod ll;

// Cursor
pub struct Cursor {
    x: ll::CXCursor
}

pub type CursorVisitor<'s> = &'s mut(FnMut(&Cursor, &Cursor) -> ll::Enum_CXChildVisitResult + 's);

impl Cursor {
    // common
    pub fn spelling(&self) -> String {
        unsafe { String_ { x: ll::clang_getCursorSpelling(self.x) }.to_string() }
    }

    pub fn kind(&self) -> ll::Enum_CXCursorKind {
        unsafe { ll::clang_getCursorKind(self.x) }
    }

    pub fn cur_type(&self) -> Type {
        unsafe { Type { x: ll::clang_getCursorType(self.x) } }
    }

    pub fn definition(&self) -> Cursor {
        unsafe { Cursor { x: ll::clang_getCursorDefinition(self.x) } }
    }

    pub fn visit(&self, mut func: CursorVisitor) {
        unsafe {
            let data = mem::transmute::<&mut CursorVisitor, ll::CXClientData>(&mut func);
            let f: extern fn(cur: ll::CXCursor, parent: ll::CXCursor,
                         data: ll::CXClientData) -> ll::Enum_CXChildVisitResult = visit_children;
            ll::clang_visitChildren(self.x, Some(f), data);
        };
    }

    pub fn enum_val(&self) -> i64 {
        unsafe { ll::clang_getEnumConstantDeclValue(self.x) as i64 }
    }

    // typedef
    pub fn typedef_type(&self) -> Type {
        unsafe { Type { x: ll::clang_getTypedefDeclUnderlyingType(self.x) } }
    }

    pub fn get_location(&self) -> usize {
        unsafe {
            let loc = ll::clang_getCursorLocation(self.x);
            let mut offset = 0;
            ll::clang_getSpellingLocation(loc, 0 as *mut _, 0 as *mut _, 0 as *mut _,
                                          &mut offset as *mut _);
            offset as usize
        }
    }
}

extern fn visit_children(cur: ll::CXCursor, parent: ll::CXCursor,
                         data: ll::CXClientData) -> ll::Enum_CXChildVisitResult {
    unsafe {
        let mut func = mem::transmute::<ll::CXClientData, &mut CursorVisitor>(data);
        return (*func)(&Cursor { x: cur }, &Cursor { x: parent });
    }
}

impl PartialEq for Cursor {
    fn eq(&self, other: &Cursor) -> bool {
        unsafe { ll::clang_equalCursors(self.x, other.x) == 1 }
    }

    fn ne(&self, other: &Cursor) -> bool {
        return !self.eq(other);
    }
}

impl Eq for Cursor {}

impl<H: Hasher+Writer> Hash<H> for Cursor {
    fn hash(&self, state: &mut H) {
        self.x.kind.hash(state);
        self.x.xdata.hash(state);
        self.x.data[0].hash(state);
        self.x.data[1].hash(state);
        self.x.data[2].hash(state);
    }
}

// type
pub struct Type {
    x: ll::CXType
}

impl Type {
    // common
    pub fn kind(&self) -> ll::Enum_CXTypeKind {
        return self.x.kind;
    }

    pub fn spelling(&self) -> String {
        unsafe { String_ { x: ll::clang_getTypeSpelling(self.x) }.to_string() }
    }

    pub fn declaration(&self) -> Cursor {
        unsafe {
            Cursor { x: ll::clang_getTypeDeclaration(self.x) }
        }
    }

    pub fn is_const(&self) -> bool {
        unsafe {
            ll::clang_isConstQualifiedType(self.x) == 1
        }
    }

    pub fn size(&self) -> usize {
        unsafe {
            let val = ll::clang_Type_getSizeOf(self.x);
            if val < 0 { 0 } else { val as usize }
        }
    }

    pub fn align(&self) -> usize {
        unsafe {
            let val = ll::clang_Type_getAlignOf(self.x);
            if val < 0 { 0 } else { val as usize }
        }
    }

    // pointer
    pub fn pointee_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getPointeeType(self.x) }
        }
    }

    // array
    pub fn elem_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getArrayElementType(self.x) }
        }
    }

    pub fn array_size(&self) -> usize {
        unsafe {
            ll::clang_getArraySize(self.x) as usize
        }
    }

    // typedef
    pub fn canonical_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getCanonicalType(self.x) }
        }
    }

    pub fn arg_types(&self) -> Vec<Type> {
        unsafe {
            let num = ll::clang_getNumArgTypes(self.x);
            let mut args = vec!();
            for i in range(0, num) {
                args.push(Type { x: ll::clang_getArgType(self.x, i as c_uint) });
            }
            return args;
        }
    }

    pub fn ret_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getResultType(self.x) }
        }
    }
}

// SourceLocation
pub struct SourceLocation {
    x: ll::CXSourceLocation
}

impl SourceLocation {
    pub fn location(&self) -> (File, usize, usize, usize) {
        unsafe {
            let mut file = ptr::null_mut();
            let mut line = 0;
            let mut col = 0;
            let mut off = 0;
            ll::clang_getSpellingLocation(self.x, &mut file, &mut line, &mut col, &mut off);
            return (File { x: file }, line as usize, col as usize, off as usize);
        }
    }
}

impl fmt::Debug for SourceLocation {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let (file, line, col, _) = self.location();
        match file.is_null() {
            false => {
                try!(write!(f, "{}", file.name()));
                try!(write!(f, ":"));
                try!(write!(f, "{}", line));
                try!(write!(f, ":"));
                write!(f, "{}", col)
            },
            true => write!(f, "builtin definitions"),
        }
    }
}

// File
pub struct File {
    x: ll::CXFile
}

impl File {
    pub fn name(&self) -> String {
        if self.is_null() {
            return "".to_string();
        }
        unsafe {
            String_ { x: ll::clang_getFileName(self.x) }.to_string()
        }
    }

    pub fn is_null(&self) -> bool {
        self.x.is_null()
    }
}

// String
pub struct String_ {
    x: ll::CXString
}

impl fmt::Display for String_ {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.x.data.is_null() {
            return "".fmt(f);
        }
        unsafe {
            let c_str = ll::clang_getCString(self.x);
            str::from_utf8(ffi::c_str_to_bytes(&c_str)).unwrap().fmt(f)
        }
    }
}

// Index
pub struct Index {
    x: ll::CXIndex
}

impl Index {
    pub fn create(pch: bool, diag: bool) -> Index {
        unsafe {
            Index { x: ll::clang_createIndex(pch as c_int, diag as c_int) }
        }
    }

    pub fn dispose(&self) {
        unsafe {
            ll::clang_disposeIndex(self.x);
        }
    }

    pub fn is_null(&self) -> bool {
        self.x.is_null()
    }
}

// TranslationUnit
pub struct TranslationUnit {
    x: ll::CXTranslationUnit
}

impl TranslationUnit {
    pub fn parse(ix: &Index, file: &Path) -> TranslationUnit {
        let _fname = ffi::CString::from_slice(file.as_vec());
        let fname = _fname.as_ptr();
        let c_args = vec!();
        let mut c_unsaved = vec!();
        let tu = unsafe {
            ll::clang_parseTranslationUnit(ix.x, fname,
                                       c_args.as_ptr(),
                                       c_args.len() as c_int,
                                       c_unsaved.as_mut_ptr(),
                                       c_unsaved.len() as c_uint,
                                       0)
        };
        TranslationUnit { x: tu }
    }

    pub fn cursor(&self) -> Cursor {
        unsafe { Cursor { x: ll::clang_getTranslationUnitCursor(self.x) } }
    }

    pub fn dispose(&self) {
        unsafe { ll::clang_disposeTranslationUnit(self.x); }
    }

    pub fn is_null(&self) -> bool {
        self.x.is_null()
    }
}
<commit_msg>update rust<commit_after>use libc::{c_uint, c_int};
use std::{ffi, str, mem, ptr};
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};

pub mod ll;

// Cursor
pub struct Cursor {
    x: ll::CXCursor
}

pub type CursorVisitor<'s> = &'s mut(FnMut(&Cursor, &Cursor) -> ll::Enum_CXChildVisitResult + 's);

impl Cursor {
    // common
    pub fn spelling(&self) -> String {
        unsafe { String_ { x: ll::clang_getCursorSpelling(self.x) }.to_string() }
    }

    pub fn kind(&self) -> ll::Enum_CXCursorKind {
        unsafe { ll::clang_getCursorKind(self.x) }
    }

    pub fn cur_type(&self) -> Type {
        unsafe { Type { x: ll::clang_getCursorType(self.x) } }
    }

    pub fn definition(&self) -> Cursor {
        unsafe { Cursor { x: ll::clang_getCursorDefinition(self.x) } }
    }

    pub fn visit(&self, mut func: CursorVisitor) {
        unsafe {
            let data = mem::transmute::<&mut CursorVisitor, ll::CXClientData>(&mut func);
            let f: extern fn(cur: ll::CXCursor, parent: ll::CXCursor,
                         data: ll::CXClientData) -> ll::Enum_CXChildVisitResult = visit_children;
            ll::clang_visitChildren(self.x, Some(f), data);
        };
    }

    pub fn enum_val(&self) -> i64 {
        unsafe { ll::clang_getEnumConstantDeclValue(self.x) as i64 }
    }

    // typedef
    pub fn typedef_type(&self) -> Type {
        unsafe { Type { x: ll::clang_getTypedefDeclUnderlyingType(self.x) } }
    }

    pub fn get_location(&self) -> usize {
        unsafe {
            let loc = ll::clang_getCursorLocation(self.x);
            let mut offset = 0;
            ll::clang_getSpellingLocation(loc, 0 as *mut _, 0 as *mut _, 0 as *mut _,
                                          &mut offset as *mut _);
            offset as usize
        }
    }
}

extern fn visit_children(cur: ll::CXCursor, parent: ll::CXCursor,
                         data: ll::CXClientData) -> ll::Enum_CXChildVisitResult {
    unsafe {
        let mut func = mem::transmute::<ll::CXClientData, &mut CursorVisitor>(data);
        return (*func)(&Cursor { x: cur }, &Cursor { x: parent });
    }
}

impl PartialEq for Cursor {
    fn eq(&self, other: &Cursor) -> bool {
        unsafe { ll::clang_equalCursors(self.x, other.x) == 1 }
    }

    fn ne(&self, other: &Cursor) -> bool {
        return !self.eq(other);
    }
}

impl Eq for Cursor {}

impl Hash for Cursor {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.x.kind.hash(state);
        self.x.xdata.hash(state);
        self.x.data[0].hash(state);
        self.x.data[1].hash(state);
        self.x.data[2].hash(state);
    }
}

// type
pub struct Type {
    x: ll::CXType
}

impl Type {
    // common
    pub fn kind(&self) -> ll::Enum_CXTypeKind {
        return self.x.kind;
    }

    pub fn spelling(&self) -> String {
        unsafe { String_ { x: ll::clang_getTypeSpelling(self.x) }.to_string() }
    }

    pub fn declaration(&self) -> Cursor {
        unsafe {
            Cursor { x: ll::clang_getTypeDeclaration(self.x) }
        }
    }

    pub fn is_const(&self) -> bool {
        unsafe {
            ll::clang_isConstQualifiedType(self.x) == 1
        }
    }

    pub fn size(&self) -> usize {
        unsafe {
            let val = ll::clang_Type_getSizeOf(self.x);
            if val < 0 { 0 } else { val as usize }
        }
    }

    pub fn align(&self) -> usize {
        unsafe {
            let val = ll::clang_Type_getAlignOf(self.x);
            if val < 0 { 0 } else { val as usize }
        }
    }

    // pointer
    pub fn pointee_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getPointeeType(self.x) }
        }
    }

    // array
    pub fn elem_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getArrayElementType(self.x) }
        }
    }

    pub fn array_size(&self) -> usize {
        unsafe {
            ll::clang_getArraySize(self.x) as usize
        }
    }

    // typedef
    pub fn canonical_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getCanonicalType(self.x) }
        }
    }

    pub fn arg_types(&self) -> Vec<Type> {
        unsafe {
            let num = ll::clang_getNumArgTypes(self.x);
            let mut args = vec!();
            for i in range(0, num) {
                args.push(Type { x: ll::clang_getArgType(self.x, i as c_uint) });
            }
            return args;
        }
    }

    pub fn ret_type(&self) -> Type {
        unsafe {
            Type { x: ll::clang_getResultType(self.x) }
        }
    }
}

// SourceLocation
pub struct SourceLocation {
    x: ll::CXSourceLocation
}

impl SourceLocation {
    pub fn location(&self) -> (File, usize, usize, usize) {
        unsafe {
            let mut file = ptr::null_mut();
            let mut line = 0;
            let mut col = 0;
            let mut off = 0;
            ll::clang_getSpellingLocation(self.x, &mut file, &mut line, &mut col, &mut off);
            return (File { x: file }, line as usize, col as usize, off as usize);
        }
    }
}

impl fmt::Debug for SourceLocation {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let (file, line, col, _) = self.location();
        match file.is_null() {
            false => {
                try!(write!(f, "{}", file.name()));
                try!(write!(f, ":"));
                try!(write!(f, "{}", line));
                try!(write!(f, ":"));
                write!(f, "{}", col)
            },
            true => write!(f, "builtin definitions"),
        }
    }
}

// File
pub struct File {
    x: ll::CXFile
}

impl File {
    pub fn name(&self) -> String {
        if self.is_null() {
            return "".to_string();
        }
        unsafe {
            String_ { x: ll::clang_getFileName(self.x) }.to_string()
        }
    }

    pub fn is_null(&self) -> bool {
        self.x.is_null()
    }
}

// String
pub struct String_ {
    x: ll::CXString
}

impl fmt::Display for String_ {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.x.data.is_null() {
            return "".fmt(f);
        }
        unsafe {
            let c_str = ll::clang_getCString(self.x);
            str::from_utf8(ffi::c_str_to_bytes(&c_str)).unwrap().fmt(f)
        }
    }
}

// Index
pub struct Index {
    x: ll::CXIndex
}

impl Index {
    pub fn create(pch: bool, diag: bool) -> Index {
        unsafe {
            Index { x: ll::clang_createIndex(pch as c_int, diag as c_int) }
        }
    }

    pub fn dispose(&self) {
        unsafe {
            ll::clang_disposeIndex(self.x);
        }
    }

    pub fn is_null(&self) -> bool {
        self.x.is_null()
    }
}

// TranslationUnit
pub struct TranslationUnit {
    x: ll::CXTranslationUnit
}

impl TranslationUnit {
    pub fn parse(ix: &Index, file: &Path) -> TranslationUnit {
        let _fname = ffi::CString::from_slice(file.as_vec());
        let fname = _fname.as_ptr();
        let c_args = vec!();
        let mut c_unsaved = vec!();
        let tu = unsafe {
            ll::clang_parseTranslationUnit(ix.x, fname,
                                       c_args.as_ptr(),
                                       c_args.len() as c_int,
                                       c_unsaved.as_mut_ptr(),
                                       c_unsaved.len() as c_uint,
                                       0)
        };
        TranslationUnit { x: tu }
    }

    pub fn cursor(&self) -> Cursor {
        unsafe { Cursor { x: ll::clang_getTranslationUnitCursor(self.x) } }
    }

    pub fn dispose(&self) {
        unsafe { ll::clang_disposeTranslationUnit(self.x); }
    }

    pub fn is_null(&self) -> bool {
        self.x.is_null()
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::error::Error;

use crate::error::{ConfigError, Unexpected};
use crate::value::{Value, ValueKind};

#[derive(serde::Deserialize, Debug)]
#[serde(untagged)]
pub enum Val {
    Null,
    Boolean(bool),
    Integer(i64),
    Float(f64),
    String(String),
    Array(Vec<Val>),
    Object(HashMap<String, Val>),
}

pub fn parse(
    uri: Option<&String>,
    text: &str,
) -> Result<HashMap<String, Value>, Box<dyn Error + Send + Sync>> {
    match json5_rs::from_str::<Val>(&text)? {
        Val::String(ref value) => Err(Unexpected::Str(value.clone())),
        Val::Integer(value) => Err(Unexpected::Integer(value)),
        Val::Float(value) => Err(Unexpected::Float(value)),
        Val::Boolean(value) => Err(Unexpected::Bool(value)),
        Val::Array(_) => Err(Unexpected::Seq),
        Val::Null => Err(Unexpected::Unit),
        Val::Object(o) => match from_json5_value(uri, Val::Object(o)).kind {
            ValueKind::Table(map) => Ok(map),
            _ => Ok(HashMap::new()),
        },
    }
    .map_err(|err| ConfigError::invalid_root(uri, err))
    .map_err(|err| Box::new(err) as Box<dyn Error + Send + Sync>)
}

fn from_json5_value(uri: Option<&String>, value: Val) -> Value {
    match value {
        Val::String(v) => Value::new(uri, ValueKind::String(v)),

        Val::Integer(v) => Value::new(uri, ValueKind::Integer(v)),

        Val::Float(v) => Value::new(uri, ValueKind::Float(v)),

        Val::Boolean(v) => Value::new(uri, ValueKind::Boolean(v)),

        Val::Object(table) => {
            let mut m = HashMap::new();

            for (key, value) in table {
                m.insert(key, from_json5_value(uri, value));
            }

            Value::new(uri, ValueKind::Table(m))
        }

        Val::Array(array) => {
            let mut l = Vec::new();

            for value in array {
                l.push(from_json5_value(uri, value));
            }

            Value::new(uri, ValueKind::Array(l))
        }

        Val::Null => Value::new(uri, ValueKind::Nil),
    }
}
<commit_msg>Simplify impl of from_json5_value()<commit_after>use std::collections::HashMap;
use std::error::Error;

use crate::error::{ConfigError, Unexpected};
use crate::value::{Value, ValueKind};

#[derive(serde::Deserialize, Debug)]
#[serde(untagged)]
pub enum Val {
    Null,
    Boolean(bool),
    Integer(i64),
    Float(f64),
    String(String),
    Array(Vec<Val>),
    Object(HashMap<String, Val>),
}

pub fn parse(
    uri: Option<&String>,
    text: &str,
) -> Result<HashMap<String, Value>, Box<dyn Error + Send + Sync>> {
    match json5_rs::from_str::<Val>(&text)? {
        Val::String(ref value) => Err(Unexpected::Str(value.clone())),
        Val::Integer(value) => Err(Unexpected::Integer(value)),
        Val::Float(value) => Err(Unexpected::Float(value)),
        Val::Boolean(value) => Err(Unexpected::Bool(value)),
        Val::Array(_) => Err(Unexpected::Seq),
        Val::Null => Err(Unexpected::Unit),
        Val::Object(o) => match from_json5_value(uri, Val::Object(o)).kind {
            ValueKind::Table(map) => Ok(map),
            _ => Ok(HashMap::new()),
        },
    }
    .map_err(|err| ConfigError::invalid_root(uri, err))
    .map_err(|err| Box::new(err) as Box<dyn Error + Send + Sync>)
}

fn from_json5_value(uri: Option<&String>, value: Val) -> Value {
    let vk = match value {
        Val::Null => ValueKind::Nil,
        Val::String(v) => ValueKind::String(v),
        Val::Integer(v) => ValueKind::Integer(v),
        Val::Float(v) => ValueKind::Float(v),
        Val::Boolean(v) => ValueKind::Boolean(v),
        Val::Object(table) => {
            let m = table
                .into_iter()
                .map(|(k, v)| (k, from_json5_value(uri, v)))
                .collect();

            ValueKind::Table(m)
        }

        Val::Array(array) => {
            let l = array
                .into_iter()
                .map(|v| from_json5_value(uri, v))
                .collect();

            ValueKind::Array(l)
        }
    };

    Value::new(uri, vk)
}
<|endoftext|>


<commit_before>
use flowgger::config::Config;
use flowgger::{Decoder, Encoder, Input};
use openssl::ssl::*;
use openssl::ssl::SslMethod::*;
use openssl::x509::X509FileType;
use std::io::{stderr, Write, BufRead, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::sync::mpsc::SyncSender;
use std::thread;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SH";
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";

#[derive(Clone)]
struct TlsConfig {
    cert: String,
    key: String,
    ciphers: String
}

pub struct TlsInput {
    listen: String,
    tls_config: TlsConfig
}

impl Input for TlsInput {
    fn new(config: &Config) -> TlsInput {
        let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().unwrap()).to_owned();
        let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().unwrap()).to_owned();
        let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().unwrap()).to_owned();
        let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_KEY, |x| x.as_str().unwrap()).to_owned();

        let tls_config = TlsConfig {
            cert: cert,
            key: key,
            ciphers: ciphers
        };
        TlsInput {
            listen: listen,
            tls_config: tls_config
        }
    }

    fn accept<TD, TE>(&self, tx: SyncSender<Vec<u8>>, decoder: TD, encoder: TE) where TD: Decoder + Clone + Send + 'static, TE: Encoder + Clone + Send + 'static {
        let listener = TcpListener::bind(&self.listen as &str).unwrap();
        for client in listener.incoming() {
            match client {
                Ok(client) => {
                    let tx = tx.clone();
                    let (decoder, encoder) = (decoder.clone(), encoder.clone());
                    let tls_config = self.tls_config.clone();
                    thread::spawn(move|| {
                        handle_client(client, tx, decoder, encoder, tls_config);
                    });
                }
                Err(_) => { }
            }
        }
    }
}

fn handle_client<TD, TE>(client: TcpStream, tx: SyncSender<Vec<u8>>, decoder: TD, encoder: TE, tls_config: TlsConfig) where TD: Decoder, TE: Encoder {
    let mut ctx = SslContext::new(Tlsv1_2).unwrap();
    ctx.set_verify(SSL_VERIFY_PEER, None); // Sigh
    ctx.set_options(SSL_OP_NO_COMPRESSION | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
    ctx.set_certificate_file(&Path::new(&tls_config.cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&tls_config.key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&tls_config.ciphers).unwrap();
    let sslclient = SslStream::accept(&ctx, client).unwrap();
    let reader = BufReader::new(sslclient);
    for line in reader.lines() {
        let line = match line {
            Err(_) => return,
            Ok(line) => line
        };
        if let Err(e) = handle_line(&line, &tx, &decoder, &encoder) {
            let _ = writeln!(stderr(), "{}: [{}]", e, line.trim());
        }
    }
}

fn handle_line<TD, TE>(line: &String, tx: &SyncSender<Vec<u8>>, decoder: &TD, encoder: &TE) -> Result<(), &'static str> where TD: Decoder, TE: Encoder {
    let decoded = try!(decoder.decode(&line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<commit_msg>Pasto<commit_after>
use flowgger::config::Config;
use flowgger::{Decoder, Encoder, Input};
use openssl::ssl::*;
use openssl::ssl::SslMethod::*;
use openssl::x509::X509FileType;
use std::io::{stderr, Write, BufRead, BufReader};
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::sync::mpsc::SyncSender;
use std::thread;

const DEFAULT_CERT: &'static str = "flowgger.pem";
const DEFAULT_CIPHERS: &'static str = "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SH";
const DEFAULT_KEY: &'static str = "flowgger.pem";
const DEFAULT_LISTEN: &'static str = "0.0.0.0:6514";

#[derive(Clone)]
struct TlsConfig {
    cert: String,
    key: String,
    ciphers: String
}

pub struct TlsInput {
    listen: String,
    tls_config: TlsConfig
}

impl Input for TlsInput {
    fn new(config: &Config) -> TlsInput {
        let listen = config.lookup("input.listen").map_or(DEFAULT_LISTEN, |x| x.as_str().unwrap()).to_owned();
        let cert = config.lookup("input.tls_cert").map_or(DEFAULT_CERT, |x| x.as_str().unwrap()).to_owned();
        let key = config.lookup("input.tls_key").map_or(DEFAULT_KEY, |x| x.as_str().unwrap()).to_owned();
        let ciphers = config.lookup("input.tls_ciphers").map_or(DEFAULT_CIPHERS, |x| x.as_str().unwrap()).to_owned();

        let tls_config = TlsConfig {
            cert: cert,
            key: key,
            ciphers: ciphers
        };
        TlsInput {
            listen: listen,
            tls_config: tls_config
        }
    }

    fn accept<TD, TE>(&self, tx: SyncSender<Vec<u8>>, decoder: TD, encoder: TE) where TD: Decoder + Clone + Send + 'static, TE: Encoder + Clone + Send + 'static {
        let listener = TcpListener::bind(&self.listen as &str).unwrap();
        for client in listener.incoming() {
            match client {
                Ok(client) => {
                    let tx = tx.clone();
                    let (decoder, encoder) = (decoder.clone(), encoder.clone());
                    let tls_config = self.tls_config.clone();
                    thread::spawn(move|| {
                        handle_client(client, tx, decoder, encoder, tls_config);
                    });
                }
                Err(_) => { }
            }
        }
    }
}

fn handle_client<TD, TE>(client: TcpStream, tx: SyncSender<Vec<u8>>, decoder: TD, encoder: TE, tls_config: TlsConfig) where TD: Decoder, TE: Encoder {
    let mut ctx = SslContext::new(Tlsv1_2).unwrap();
    ctx.set_verify(SSL_VERIFY_PEER, None); // Sigh
    ctx.set_options(SSL_OP_NO_COMPRESSION | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
    ctx.set_certificate_file(&Path::new(&tls_config.cert), X509FileType::PEM).unwrap();
    ctx.set_private_key_file(&Path::new(&tls_config.key), X509FileType::PEM).unwrap();
    ctx.set_cipher_list(&tls_config.ciphers).unwrap();
    let sslclient = SslStream::accept(&ctx, client).unwrap();
    let reader = BufReader::new(sslclient);
    for line in reader.lines() {
        let line = match line {
            Err(_) => return,
            Ok(line) => line
        };
        if let Err(e) = handle_line(&line, &tx, &decoder, &encoder) {
            let _ = writeln!(stderr(), "{}: [{}]", e, line.trim());
        }
    }
}

fn handle_line<TD, TE>(line: &String, tx: &SyncSender<Vec<u8>>, decoder: &TD, encoder: &TE) -> Result<(), &'static str> where TD: Decoder, TE: Encoder {
    let decoded = try!(decoder.decode(&line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path;
use toml;
use game::*;
use direction::*;

type ControlSpec = HashMap<String, String>;

impl<'a> From<&'a ControlMap> for ControlSpec {
    fn from(map: &'a ControlMap) -> Self {
        let mut spec = ControlSpec::new();

        for (input_event, control) in map.iter() {
            spec.insert(String::from(*control), String::from(*input_event));
        }

        spec
    }
}

impl<'a> From<&'a ControlSpec> for ControlMap {
    fn from(spec: &'a ControlSpec) -> Self {
        let mut map = ControlMap::new();

        for (control, input) in spec.iter() {
            map.insert(InputEvent::from(input), Control::from(control));
        }

        map
    }
}

impl<'a> From<&'a String> for Control {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "North" => Control::Direction(Direction::North),
            "South" => Control::Direction(Direction::South),
            "East" => Control::Direction(Direction::East),
            "West" => Control::Direction(Direction::West),
            "Use" => Control::Use,
            "Close" => Control::Close,
            "Examine" => Control::Examine,
            "Wait" => Control::Wait,
            "Fire" => Control::Fire,
            "NextTarget" => Control::NextTarget,
            "PrevTarget" => Control::PrevTarget,
            "DisplayMessageLog" => Control::DisplayMessageLog,
            "Pause" => Control::Pause,
            _ => panic!("No such control: {}", s),
        }
    }
}

impl From<Control> for String {
    fn from(control: Control) -> Self {
        match control {
            Control::Direction(Direction::North) => "North",
            Control::Direction(Direction::South) => "South",
            Control::Direction(Direction::East) => "East",
            Control::Direction(Direction::West) => "West",
            Control::Use => "Use",
            Control::Close => "Close",
            Control::Examine => "Examine",
            Control::Wait => "Wait",
            Control::Fire => "Fire",
            Control::NextTarget => "NextTarget",
            Control::PrevTarget => "PrevTarget",
            Control::DisplayMessageLog => "DisplayMessageLog",
            Control::Pause => "Pause",
            _ => panic!("Unencodable control: {:?}", control),
        }.to_string()
    }
}

impl From<InputEvent> for String {
    fn from(input: InputEvent) -> Self {
        match input {
            InputEvent::Char(c) => return format!("{}", c),
            InputEvent::Up => "Up",
            InputEvent::Down => "Down",
            InputEvent::Left => "Left",
            InputEvent::Right => "Right",
            InputEvent::Escape => "Escape",
            InputEvent::Return => "Return",
            InputEvent::Space => "Space",
            InputEvent::Quit => panic!("Quit is not a key"),
        }.to_string()
    }
}

impl<'a> From<&'a String> for InputEvent {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "Up" => return InputEvent::Up,
            "Down" => return InputEvent::Down,
            "Left" => return InputEvent::Left,
            "Right" => return InputEvent::Right,
            "Escape" => return InputEvent::Escape,
            "Return" => return InputEvent::Return,
            "Space" => return InputEvent::Space,
            _ => (),
        }

        if s.len() == 1 {
            if let Some(c) = s.chars().next() {
                return InputEvent::Char(c);
            }
        }

        panic!("No such input: {}", s);
    }
}

fn parse_control(name: &str) -> Option<Control> {

    let control = match name {
        "North" => Control::Direction(Direction::North),
        "South" => Control::Direction(Direction::South),
        "East" => Control::Direction(Direction::East),
        "West" => Control::Direction(Direction::West),
        "Use" => Control::Use,
        "Close" => Control::Close,
        "Examine" => Control::Examine,
        "Wait" => Control::Wait,
        "Fire" => Control::Fire,
        "NextTarget" => Control::NextTarget,
        "PrevTarget" => Control::PrevTarget,
        "DisplayMessageLog" => Control::DisplayMessageLog,
        "Pause" => Control::Pause,
        _ => return None,
    };

    Some(control)
}

fn parse_input_event(string: &str) -> Option<InputEvent> {
    match string {
        "Up" => return Some(InputEvent::Up),
        "Down" => return Some(InputEvent::Down),
        "Left" => return Some(InputEvent::Left),
        "Right" => return Some(InputEvent::Right),
        "Escape" => return Some(InputEvent::Escape),
        "Return" => return Some(InputEvent::Return),
        _ => {},
    }

    if string.len() == 1 {
        if let Some(c) = string.chars().next() {
            return Some(InputEvent::Char(c));
        }
    }

    None
}

fn from_toml(table: toml::value::Table) -> Option<ControlMap> {
    table.get("controls")
        .and_then(|t| t.as_table())
        .map(|controls| {
            let mut control_map = ControlMap::new();

            for (control_str, input_event_str) in controls.iter() {
                if let Some(control) = parse_control(control_str.as_str()) {
                    if let Some(input_event) = input_event_str.as_str().and_then(parse_input_event) {
                        control_map.insert(input_event, control);
                    }
                }
            }

            control_map
        })
}

pub fn from_file<P: AsRef<path::Path>>(path: P) -> Option<ControlMap> {
    let spec: Option<ControlSpec> = game_file::read_toml(path).ok();
    spec.as_ref().map(ControlMap::from)
}

pub fn to_file<P: AsRef<path::Path>>(path: P, map: &ControlMap) {
    game_file::write_toml(path, &ControlSpec::from(map))
        .expect("Failed to write controls file");
}
<commit_msg>Renamed ControlSpec to StringControlSpec<commit_after>use std::collections::HashMap;
use std::path;
use toml;
use game::*;
use direction::*;

type StringControlSpec = HashMap<String, String>;

impl<'a> From<&'a ControlMap> for StringControlSpec {
    fn from(map: &'a ControlMap) -> Self {
        let mut spec = StringControlSpec::new();

        for (input_event, control) in map.iter() {
            spec.insert(String::from(*control), String::from(*input_event));
        }

        spec
    }
}

impl<'a> From<&'a StringControlSpec> for ControlMap {
    fn from(spec: &'a StringControlSpec) -> Self {
        let mut map = ControlMap::new();

        for (control, input) in spec.iter() {
            map.insert(InputEvent::from(input), Control::from(control));
        }

        map
    }
}

impl<'a> From<&'a String> for Control {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "North" => Control::Direction(Direction::North),
            "South" => Control::Direction(Direction::South),
            "East" => Control::Direction(Direction::East),
            "West" => Control::Direction(Direction::West),
            "Use" => Control::Use,
            "Close" => Control::Close,
            "Examine" => Control::Examine,
            "Wait" => Control::Wait,
            "Fire" => Control::Fire,
            "NextTarget" => Control::NextTarget,
            "PrevTarget" => Control::PrevTarget,
            "DisplayMessageLog" => Control::DisplayMessageLog,
            "Pause" => Control::Pause,
            _ => panic!("No such control: {}", s),
        }
    }
}

impl From<Control> for String {
    fn from(control: Control) -> Self {
        match control {
            Control::Direction(Direction::North) => "North",
            Control::Direction(Direction::South) => "South",
            Control::Direction(Direction::East) => "East",
            Control::Direction(Direction::West) => "West",
            Control::Use => "Use",
            Control::Close => "Close",
            Control::Examine => "Examine",
            Control::Wait => "Wait",
            Control::Fire => "Fire",
            Control::NextTarget => "NextTarget",
            Control::PrevTarget => "PrevTarget",
            Control::DisplayMessageLog => "DisplayMessageLog",
            Control::Pause => "Pause",
            _ => panic!("Unencodable control: {:?}", control),
        }.to_string()
    }
}

impl From<InputEvent> for String {
    fn from(input: InputEvent) -> Self {
        match input {
            InputEvent::Char(c) => return format!("{}", c),
            InputEvent::Up => "Up",
            InputEvent::Down => "Down",
            InputEvent::Left => "Left",
            InputEvent::Right => "Right",
            InputEvent::Escape => "Escape",
            InputEvent::Return => "Return",
            InputEvent::Space => "Space",
            InputEvent::Quit => panic!("Quit is not a key"),
        }.to_string()
    }
}

impl<'a> From<&'a String> for InputEvent {
    fn from(s: &'a String) -> Self {
        match s.as_ref() {
            "Up" => return InputEvent::Up,
            "Down" => return InputEvent::Down,
            "Left" => return InputEvent::Left,
            "Right" => return InputEvent::Right,
            "Escape" => return InputEvent::Escape,
            "Return" => return InputEvent::Return,
            "Space" => return InputEvent::Space,
            _ => (),
        }

        if s.len() == 1 {
            if let Some(c) = s.chars().next() {
                return InputEvent::Char(c);
            }
        }

        panic!("No such input: {}", s);
    }
}

fn parse_control(name: &str) -> Option<Control> {

    let control = match name {
        "North" => Control::Direction(Direction::North),
        "South" => Control::Direction(Direction::South),
        "East" => Control::Direction(Direction::East),
        "West" => Control::Direction(Direction::West),
        "Use" => Control::Use,
        "Close" => Control::Close,
        "Examine" => Control::Examine,
        "Wait" => Control::Wait,
        "Fire" => Control::Fire,
        "NextTarget" => Control::NextTarget,
        "PrevTarget" => Control::PrevTarget,
        "DisplayMessageLog" => Control::DisplayMessageLog,
        "Pause" => Control::Pause,
        _ => return None,
    };

    Some(control)
}

fn parse_input_event(string: &str) -> Option<InputEvent> {
    match string {
        "Up" => return Some(InputEvent::Up),
        "Down" => return Some(InputEvent::Down),
        "Left" => return Some(InputEvent::Left),
        "Right" => return Some(InputEvent::Right),
        "Escape" => return Some(InputEvent::Escape),
        "Return" => return Some(InputEvent::Return),
        _ => {},
    }

    if string.len() == 1 {
        if let Some(c) = string.chars().next() {
            return Some(InputEvent::Char(c));
        }
    }

    None
}

fn from_toml(table: toml::value::Table) -> Option<ControlMap> {
    table.get("controls")
        .and_then(|t| t.as_table())
        .map(|controls| {
            let mut control_map = ControlMap::new();

            for (control_str, input_event_str) in controls.iter() {
                if let Some(control) = parse_control(control_str.as_str()) {
                    if let Some(input_event) = input_event_str.as_str().and_then(parse_input_event) {
                        control_map.insert(input_event, control);
                    }
                }
            }

            control_map
        })
}

pub fn from_file<P: AsRef<path::Path>>(path: P) -> Option<ControlMap> {
    let spec: Option<StringControlSpec> = game_file::read_toml(path).ok();
    spec.as_ref().map(ControlMap::from)
}

pub fn to_file<P: AsRef<path::Path>>(path: P, map: &ControlMap) {
    game_file::write_toml(path, &StringControlSpec::from(map))
        .expect("Failed to write controls file");
}
<|endoftext|>


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

#![crate_name = "glfw_platform"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(macro_rules, phase)]

extern crate glfw;
#[phase(plugin, link)]
extern crate log;
extern crate libc;

extern crate device;

use glfw::Context;

struct Wrap<'a>(&'a glfw::Glfw);

impl<'a> device::GlProvider for Wrap<'a> {
    fn get_proc_address(&self, name: &str) -> *const libc::c_void {
        let Wrap(provider) = *self;
        provider.get_proc_address(name)
    }
    fn is_extension_supported(&self, name: &str) -> bool {
        let Wrap(provider) = *self;
        provider.extension_supported(name)
    }
}

pub struct Platform<C> {
    pub context: C,
}

impl<C: Context> Platform<C> {
    #[allow(visible_private_types)]
    pub fn new<'a>(context: C, provider: &'a glfw::Glfw) -> (Platform<C>, Wrap<'a>)  {
        context.make_current();
        (Platform { context: context }, Wrap(provider))
    }
}

impl<C: Context> device::GraphicsContext<device::GlBackEnd> for Platform<C> {
    fn make_current(&self) {
        self.context.make_current();
    }

    fn swap_buffers(&self) {
        self.context.swap_buffers();
    }
}

pub fn create_window<'glfw, 'title, 'monitor, 'setup>(
    glfw: &'glfw glfw::Glfw,
    width: u32,
    height: u32,
    title: &'title str,
    mode: glfw::WindowMode<'monitor>,
    preferred_setup: |&glfw::Glfw|:'setup,
) -> CreateWindow<'glfw, 'title, 'monitor, 'setup> {
    CreateWindow {
        glfw: glfw,
        args: (width, height, title, mode),
        setups: vec![preferred_setup],
        finally: None,
    }
}

pub fn create_default_window(
    glfw: &glfw::Glfw,
    width: u32,
    height: u32,
    title: &str,
    mode: glfw::WindowMode
) -> Option<(glfw::Window, Receiver<(f64, glfw::WindowEvent)>)> {
    create_window(glfw, width, height, title, mode, |glfw| {
        info!("[glfw_platform] Trying to initialize with context version 3.2 core");
        glfw.default_window_hints();
        glfw.window_hint(glfw::ContextVersion(3, 2));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
    })
    .fallback(|glfw| {
        info!("[glfw_platform] Trying to initialize with context version 2.1");
        glfw.default_window_hints();
        glfw.window_hint(glfw::ContextVersion(2, 1));
    })
    .apply().map(|(window, events)| {
        info!("[glfw_platform] Initialized with context version {}", window.get_context_version());
        (window, events)
    })
}

pub struct CreateWindow<'glfw, 'title, 'monitor, 'setup> {
    glfw: &'glfw glfw::Glfw,
    args: (u32, u32, &'title str, glfw::WindowMode<'monitor>),
    setups: Vec<|&glfw::Glfw|:'setup>,
    finally: Option<|&glfw::Glfw|:'setup>,
}

impl<'glfw, 'title, 'monitor, 'setup> CreateWindow<'glfw, 'title, 'monitor, 'setup> {
    pub fn fallback(mut self, f: |&glfw::Glfw|:'setup)
    -> CreateWindow<'glfw, 'title, 'monitor, 'setup> {
        self.setups.push(f);
        self
    }
    pub fn apply(self) -> Option<(glfw::Window, Receiver<(f64, glfw::WindowEvent)>)> {
        let CreateWindow {
            glfw,
            mut setups,
            finally,
            args: (width, height, title, mode),
        } = self;

        glfw.set_error_callback::<()>(None);
        for setup in setups.mut_iter() {
            (*setup)(glfw);
            let r = glfw.create_window(width, height, title, mode);
            if r.is_some() {
                match finally {
                    Some(f) => f(glfw),
                    None => (),
                }
                return r;
            }
        }
        None
    }
}
<commit_msg>Made gfx::glfw::create_window take arrays of window hints, instead of callbacks<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "glfw_platform"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(macro_rules, phase)]

extern crate glfw;
#[phase(plugin, link)]
extern crate log;
extern crate libc;

extern crate device;

use glfw::Context;

struct Wrap<'a>(&'a glfw::Glfw);

impl<'a> device::GlProvider for Wrap<'a> {
    fn get_proc_address(&self, name: &str) -> *const libc::c_void {
        let Wrap(provider) = *self;
        provider.get_proc_address(name)
    }
    fn is_extension_supported(&self, name: &str) -> bool {
        let Wrap(provider) = *self;
        provider.extension_supported(name)
    }
}

pub struct Platform<C> {
    pub context: C,
}

impl<C: Context> Platform<C> {
    #[allow(visible_private_types)]
    pub fn new<'a>(context: C, provider: &'a glfw::Glfw) -> (Platform<C>, Wrap<'a>)  {
        context.make_current();
        (Platform { context: context }, Wrap(provider))
    }
}

impl<C: Context> device::GraphicsContext<device::GlBackEnd> for Platform<C> {
    fn make_current(&self) {
        self.context.make_current();
    }

    fn swap_buffers(&self) {
        self.context.swap_buffers();
    }
}

pub fn create_window<'glfw, 'title, 'monitor, 'hints>(
    glfw: &'glfw glfw::Glfw,
    width: u32,
    height: u32,
    title: &'title str,
    mode: glfw::WindowMode<'monitor>,
    preferred_setup: &'hints [glfw::WindowHint],
) -> CreateWindow<'glfw, 'title, 'monitor, 'hints> {
    CreateWindow {
        glfw: glfw,
        args: (width, height, title, mode),
        hints: vec![preferred_setup],
    }
}

pub fn create_default_window(
    glfw: &glfw::Glfw,
    width: u32,
    height: u32,
    title: &str,
    mode: glfw::WindowMode
) -> Option<(glfw::Window, Receiver<(f64, glfw::WindowEvent)>)> {
    create_window(glfw, width, height, title, mode, [
        glfw::ContextVersion(3, 2),
        glfw::OpenglForwardCompat(true),
        glfw::OpenglProfile(glfw::OpenGlCoreProfile),
    ])
    .fallback([
        glfw::ContextVersion(2, 1),
    ])
    .apply().map(|(window, events)| {
        info!("[glfw_platform] Initialized with context version {}", window.get_context_version());
        (window, events)
    })
}

pub struct CreateWindow<'glfw, 'title, 'monitor, 'hints> {
    glfw: &'glfw glfw::Glfw,
    args: (u32, u32, &'title str, glfw::WindowMode<'monitor>),
    hints: Vec<&'hints [glfw::WindowHint]>,
}

impl<'glfw, 'title, 'monitor, 'hints> CreateWindow<'glfw, 'title, 'monitor, 'hints> {
    pub fn fallback(mut self, f: &'hints [glfw::WindowHint])
    -> CreateWindow<'glfw, 'title, 'monitor, 'hints> {
        self.hints.push(f);
        self
    }
    pub fn apply(self) -> Option<(glfw::Window, Receiver<(f64, glfw::WindowEvent)>)> {
        let CreateWindow {
            glfw,
            mut hints,
            args: (width, height, title, mode),
        } = self;

        glfw.set_error_callback::<()>(None);
        for setup in hints.mut_iter() {
            glfw.default_window_hints();
            for hint in setup.iter() {
                glfw.window_hint(*hint);
            }
            let r = glfw.create_window(width, height, title, mode);
            if r.is_some() {
                return r;
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms},
    gpu::arc::ArcBuffer,
    Image,
};
use crevice::std140::{AsStd140, Std140};

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug, Clone)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    pub(crate) image: Image,
    capacity: u32,
    len: u32,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    pub fn new(gfx: &GraphicsContext, image: impl Into<Option<Image>>, capacity: u32) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(gfx.wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let image = image.into().unwrap_or_else(|| gfx.white_image.clone());

        InstanceArray {
            buffer,
            image,
            capacity,
            len: 0,
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    ///
    /// Prefer this over `push` where possible.
    #[allow(unsafe_code)]
    pub fn set<I>(&mut self, gfx: &GraphicsContext, instances: I)
    where
        I: IntoIterator<Item = DrawParam>,
    {
        let instances = instances
            .into_iter()
            .map(|param| {
                DrawUniforms::from_param(
                    param,
                    [self.image.width() as f32, self.image.height() as f32].into(),
                )
                .as_std140()
            })
            .collect::<Vec<_>>();

        let len = instances.len() as u32;
        if len > self.capacity {
            self.resize_impl(gfx, len, false);
        }

        self.len = instances.len() as u32;
        gfx.wgpu.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                instances.as_ptr() as *const u8,
                instances.len() * DrawUniforms::std140_size_static(),
            )
        });
    }

    /// Pushes a new instance onto the end.
    ///
    /// Prefer `set` where bulk instances needs to be set.
    pub fn push(&mut self, gfx: &GraphicsContext, instance: DrawParam) {
        if self.len == self.capacity {
            self.resize(gfx, self.capacity + self.capacity / 2);
        }

        let instance = DrawUniforms::from_param(
            instance,
            [self.image.width() as f32, self.image.height() as f32].into(),
        );
        gfx.wgpu.queue.write_buffer(
            &self.buffer,
            self.len as u64 * DrawUniforms::std140_size_static() as u64,
            instance.as_std140().as_bytes(),
        );
        self.len += 1;
    }

    /// Updates an existing instance at a given index.
    pub fn update(&mut self, gfx: &GraphicsContext, index: u32, instance: DrawParam) {
        assert!(index < self.len, "index out of range");

        let instance = DrawUniforms::from_param(
            instance,
            [self.image.width() as f32, self.image.height() as f32].into(),
        );
        gfx.wgpu.queue.write_buffer(
            &self.buffer,
            index as u64 * DrawUniforms::std140_size_static() as u64,
            instance.as_std140().as_bytes(),
        );
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        self.len = 0;
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &GraphicsContext, new_capacity: u32) {
        self.resize_impl(gfx, new_capacity, true)
    }

    fn resize_impl(&mut self, gfx: &GraphicsContext, new_capacity: u32, copy: bool) {
        let mut resized = InstanceArray::new(gfx, self.image.clone(), new_capacity);
        resized.len = new_capacity.min(self.len);

        if copy {
            let cmd = {
                let mut cmd = gfx.wgpu.device.create_command_encoder(&Default::default());
                cmd.copy_buffer_to_buffer(
                    &self.buffer,
                    0,
                    &resized.buffer,
                    0,
                    new_capacity.min(self.len) as u64 * DrawUniforms::std140_size_static() as u64,
                );
                cmd.finish()
            };
            gfx.wgpu.queue.submit([cmd]);
        }

        *self = resized;
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray].
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }

    /// Returns the number of instances.
    #[inline]
    pub fn len(&self) -> usize {
        self.len as usize
    }
}
<commit_msg>make instancearray len arc/atomic<commit_after>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms},
    gpu::arc::ArcBuffer,
    Image,
};
use crevice::std140::{AsStd140, Std140};
use std::sync::{
    atomic::{AtomicU32, Ordering::SeqCst},
    Arc,
};

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug, Clone)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    pub(crate) image: Image,
    capacity: u32,
    len: Arc<AtomicU32>,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    pub fn new(gfx: &GraphicsContext, image: impl Into<Option<Image>>, capacity: u32) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(gfx.wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let image = image.into().unwrap_or_else(|| gfx.white_image.clone());

        InstanceArray {
            buffer,
            image,
            capacity,
            len: Arc::new(AtomicU32::new(0)),
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    ///
    /// Prefer this over `push` where possible.
    #[allow(unsafe_code)]
    pub fn set<I>(&mut self, gfx: &GraphicsContext, instances: I)
    where
        I: IntoIterator<Item = DrawParam>,
    {
        let instances = instances
            .into_iter()
            .map(|param| {
                DrawUniforms::from_param(
                    param,
                    [self.image.width() as f32, self.image.height() as f32].into(),
                )
                .as_std140()
            })
            .collect::<Vec<_>>();

        let len = instances.len() as u32;
        if len > self.capacity {
            self.resize_impl(gfx, len, false);
        }

        self.len.store(instances.len() as u32, SeqCst);
        gfx.wgpu.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                instances.as_ptr() as *const u8,
                instances.len() * DrawUniforms::std140_size_static(),
            )
        });
    }

    /// Pushes a new instance onto the end.
    ///
    /// Prefer `set` where bulk instances needs to be set.
    pub fn push(&mut self, gfx: &GraphicsContext, instance: DrawParam) {
        if self.len.load(SeqCst) == self.capacity {
            self.resize(gfx, self.capacity + self.capacity / 2);
        }

        let instance = DrawUniforms::from_param(
            instance,
            [self.image.width() as f32, self.image.height() as f32].into(),
        );
        gfx.wgpu.queue.write_buffer(
            &self.buffer,
            self.len.load(SeqCst) as u64 * DrawUniforms::std140_size_static() as u64,
            instance.as_std140().as_bytes(),
        );
        let _ = self.len.fetch_add(1, SeqCst);
    }

    /// Updates an existing instance at a given index.
    pub fn update(&mut self, gfx: &GraphicsContext, index: u32, instance: DrawParam) {
        assert!(index < self.len.load(SeqCst), "index out of range");

        let instance = DrawUniforms::from_param(
            instance,
            [self.image.width() as f32, self.image.height() as f32].into(),
        );
        gfx.wgpu.queue.write_buffer(
            &self.buffer,
            index as u64 * DrawUniforms::std140_size_static() as u64,
            instance.as_std140().as_bytes(),
        );
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        self.len.store(0, SeqCst);
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &GraphicsContext, new_capacity: u32) {
        self.resize_impl(gfx, new_capacity, true)
    }

    fn resize_impl(&mut self, gfx: &GraphicsContext, new_capacity: u32, copy: bool) {
        let len = self.len.load(SeqCst);
        let resized = InstanceArray::new(gfx, self.image.clone(), new_capacity);
        resized.len.store(new_capacity.min(len), SeqCst);

        if copy {
            let cmd = {
                let mut cmd = gfx.wgpu.device.create_command_encoder(&Default::default());
                cmd.copy_buffer_to_buffer(
                    &self.buffer,
                    0,
                    &resized.buffer,
                    0,
                    new_capacity.min(len) as u64 * DrawUniforms::std140_size_static() as u64,
                );
                cmd.finish()
            };
            gfx.wgpu.queue.submit([cmd]);
        }

        *self = resized;
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray].
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }

    /// Returns the number of instances.
    #[inline]
    pub fn len(&self) -> usize {
        self.len.load(SeqCst) as usize
    }
}
<|endoftext|>