<commit_before>//! Create textures and build texture atlas.

use gfx::CommandBuffer;
use gfx::Device;
use image;
use image::{ GenericImage, ImageBuffer, RgbaImage, Pixel, SubImage };
use std::num::Float;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::mem;

pub use gfx_texture::Texture;

/// Loads RGBA image from path.
fn load_rgba8(path: &Path) -> Result<RgbaImage, String> {
    Ok(match image::open(path) {
        Ok(image::ImageRgba8(img)) => img,
        Ok(image::ImageRgb8(img)) => {
            let (w, h) = img.dimensions();
            // We're forced to use Box::new on the closure because ImageBuffer
            // is defined in the "image" crate.
            ImageBuffer::from_fn(w, h, Box::new(|&: x, y| img.get_pixel(x, y).to_rgba()))
        }
        Ok(img) => {
            return Err(format!("Unsupported color type {:?} in '{}'",
                img.color(), path.display()));
        }
        Err(e)  => {
            return Err(format!("Could not load '{}': {:?}", path.display(), e));
        }
    })
}

/// A 256x256 image that stores colors.
pub struct ColorMap {
    image: RgbaImage
}

impl ColorMap {
    /// Creates a new `ColorMap` from path.
    pub fn from_path(path: &Path) -> Result<ColorMap, String> {
        let img = try!(load_rgba8(path));

        match img.dimensions() {
            (256, 256) => Ok(ColorMap {image: img}),
            (w, h) => Err(format!("ColorMap expected 256x256, found {}x{} in '{}'",
                                  w, h, path.display()))
        }
    }

    /// Gets RGB color from the color map.
    pub fn get(&self, x: f32, y: f32) -> [u8; 3] {
        // Clamp to [0.0, 1.0].
        let x = x.max(0.0).min(1.0);
        let y = y.max(0.0).min(1.0);

        // Scale y from [0.0, 1.0] to [0.0, x], forming a triangle.
        let y = x * y;

        // Origin is in the bottom-right corner.
        let x = ((1.0 - x) * 255.0) as u8;
        let y = ((1.0 - y) * 255.0) as u8;

        let col = self.image.get_pixel(x as u32, y as u32).channels();
        [col[0], col[1], col[2]]
    }
}

/// Builds an atlas of textures.
pub struct AtlasBuilder {
    image: RgbaImage,
    // Base path for loading tiles.
    path: Path,
    // Size of an individual tile.
    unit_width: u32,
    unit_height: u32,
    // Size of the entirely occupied square, in tiles.
    completed_tiles_size: u32,
    // Position in the current strip.
    position: u32,
    // Position cache for loaded tiles (in pixels).
    tile_positions: HashMap<String, (u32, u32)>,
    // Lowest-alpha cache for rectangles in the atlas.
    min_alpha_cache: HashMap<(u32, u32, u32, u32), u8>
}

impl AtlasBuilder {
    /// Creates a new `AtlasBuilder`.
    pub fn new(path: Path, unit_width: u32, unit_height: u32) -> AtlasBuilder {
        AtlasBuilder {
            image: ImageBuffer::new(unit_width * 4, unit_height * 4),
            path: path,
            unit_width: unit_width,
            unit_height: unit_height,
            completed_tiles_size: 0,
            position: 0,
            tile_positions: HashMap::new(),
            min_alpha_cache: HashMap::new()
        }
    }

    /// Loads a file into the texture atlas.
    /// Checks if the file is loaded and returns position within the atlas.
    /// The name should be specified without file extension.
    /// PNG is the only supported format.
    pub fn load(&mut self, name: &str) -> (u32, u32) {
        match self.tile_positions.get(name) {
            Some(pos) => return *pos,
            None => {}
        }

        let mut path = self.path.join(name);
        path.set_extension("png");
        let img = load_rgba8(&path).unwrap();

        let (iw, ih) = img.dimensions();
        assert!(iw == self.unit_width);
        assert!((ih % self.unit_height) == 0);
        if ih > self.unit_height {
            println!("ignoring {} extra frames in '{}'", (ih / self.unit_height) - 1, name);
        }

        let (uw, uh) = (self.unit_width, self.unit_height);
        let (w, h) = self.image.dimensions();
        let size = self.completed_tiles_size;

        // Expand the image buffer if necessary.
        if self.position == 0 && (uw * size >= w || uh * size >= h) {
            let old = mem::replace(&mut self.image, ImageBuffer::new(w * 2, h * 2));
            for ix in range(0, w) {
                for iy in range(0, h) {
                    *self.image.get_pixel_mut(ix, iy) = old[(ix, iy)];
                }
            }

            /*
            let mut dest = SubImage::new(&mut self.image, 0, 0, w, h);
            for ((_, _, a), b) in dest.pixels_mut().zip(old.pixels()) {
                *a = *b;
            }
            */
        }

        let (x, y) = if self.position < size {
            (self.position, size)
        } else {
            (size, self.position - size)
        };

        self.position += 1;
        if self.position >= size * 2 + 1 {
            self.position = 0;
            self.completed_tiles_size += 1;
        }

        {
            let [x, y, w, h] = [x * uw, y * uh, uw, uh];
            for ix in range(0, w) {
                for iy in range(0, h) {
                    *self.image.get_pixel_mut(ix + x, iy + y) = img[(ix, iy)];
                }
            }
        }

        /*
        let mut dest = SubImage::new(&mut self.image, x * uw, y * uh, uw, uh);
        for ((_, _, a), b) in dest.pixels_mut().zip(img.pixels()) {
            *a = *b;
        }
        */

        *match self.tile_positions.entry(name.to_string()) {
            Occupied(entry) => entry.into_mut(),
            Vacant(entry) => entry.insert((x * uw, y * uh))
        }
    }

    /// Finds the minimum alpha value in a given sub texture of the image.
    pub fn min_alpha(&mut self, rect: [u32; 4]) -> u8 {
        let [x, y, w, h] = rect;
        match self.min_alpha_cache.get(&(x, y, w, h)) {
            Some(alpha) => return *alpha,
            None => {}
        }

        let tile = SubImage::new(&mut self.image, x, y, w, h);
        let min_alpha = tile.pixels().map(|(_, _, p)| p[3])
            .min().unwrap_or(0);
        self.min_alpha_cache.insert((x, y, w, h), min_alpha);
        min_alpha
    }

    /// Returns the complete texture atlas as a texture.
    pub fn complete<D: Device>(self, d: &mut D) -> Texture {
        Texture::from_rgba8::<D>(self.image, d)
    }
}
<commit_msg>Remove leftovers.<commit_after>//! Create textures and build texture atlas.

use gfx::CommandBuffer;
use gfx::Device;
use image;
use image::{ GenericImage, ImageBuffer, RgbaImage, Pixel, SubImage };
use std::num::Float;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::mem;

pub use gfx_texture::Texture;

/// Loads RGBA image from path.
fn load_rgba8(path: &Path) -> Result<RgbaImage, String> {
    Ok(match image::open(path) {
        Ok(image::ImageRgba8(img)) => img,
        Ok(image::ImageRgb8(img)) => {
            let (w, h) = img.dimensions();
            // We're forced to use Box::new on the closure because ImageBuffer
            // is defined in the "image" crate.
            ImageBuffer::from_fn(w, h, Box::new(|&: x, y| img.get_pixel(x, y).to_rgba()))
        }
        Ok(img) => {
            return Err(format!("Unsupported color type {:?} in '{}'",
                img.color(), path.display()));
        }
        Err(e)  => {
            return Err(format!("Could not load '{}': {:?}", path.display(), e));
        }
    })
}

/// A 256x256 image that stores colors.
pub struct ColorMap {
    image: RgbaImage
}

impl ColorMap {
    /// Creates a new `ColorMap` from path.
    pub fn from_path(path: &Path) -> Result<ColorMap, String> {
        let img = try!(load_rgba8(path));

        match img.dimensions() {
            (256, 256) => Ok(ColorMap {image: img}),
            (w, h) => Err(format!("ColorMap expected 256x256, found {}x{} in '{}'",
                                  w, h, path.display()))
        }
    }

    /// Gets RGB color from the color map.
    pub fn get(&self, x: f32, y: f32) -> [u8; 3] {
        // Clamp to [0.0, 1.0].
        let x = x.max(0.0).min(1.0);
        let y = y.max(0.0).min(1.0);

        // Scale y from [0.0, 1.0] to [0.0, x], forming a triangle.
        let y = x * y;

        // Origin is in the bottom-right corner.
        let x = ((1.0 - x) * 255.0) as u8;
        let y = ((1.0 - y) * 255.0) as u8;

        let col = self.image.get_pixel(x as u32, y as u32).channels();
        [col[0], col[1], col[2]]
    }
}

/// Builds an atlas of textures.
pub struct AtlasBuilder {
    image: RgbaImage,
    // Base path for loading tiles.
    path: Path,
    // Size of an individual tile.
    unit_width: u32,
    unit_height: u32,
    // Size of the entirely occupied square, in tiles.
    completed_tiles_size: u32,
    // Position in the current strip.
    position: u32,
    // Position cache for loaded tiles (in pixels).
    tile_positions: HashMap<String, (u32, u32)>,
    // Lowest-alpha cache for rectangles in the atlas.
    min_alpha_cache: HashMap<(u32, u32, u32, u32), u8>
}

impl AtlasBuilder {
    /// Creates a new `AtlasBuilder`.
    pub fn new(path: Path, unit_width: u32, unit_height: u32) -> AtlasBuilder {
        AtlasBuilder {
            image: ImageBuffer::new(unit_width * 4, unit_height * 4),
            path: path,
            unit_width: unit_width,
            unit_height: unit_height,
            completed_tiles_size: 0,
            position: 0,
            tile_positions: HashMap::new(),
            min_alpha_cache: HashMap::new()
        }
    }

    /// Loads a file into the texture atlas.
    /// Checks if the file is loaded and returns position within the atlas.
    /// The name should be specified without file extension.
    /// PNG is the only supported format.
    pub fn load(&mut self, name: &str) -> (u32, u32) {
        match self.tile_positions.get(name) {
            Some(pos) => return *pos,
            None => {}
        }

        let mut path = self.path.join(name);
        path.set_extension("png");
        let img = load_rgba8(&path).unwrap();

        let (iw, ih) = img.dimensions();
        assert!(iw == self.unit_width);
        assert!((ih % self.unit_height) == 0);
        if ih > self.unit_height {
            println!("ignoring {} extra frames in '{}'", (ih / self.unit_height) - 1, name);
        }

        let (uw, uh) = (self.unit_width, self.unit_height);
        let (w, h) = self.image.dimensions();
        let size = self.completed_tiles_size;

        // Expand the image buffer if necessary.
        if self.position == 0 && (uw * size >= w || uh * size >= h) {
            let old = mem::replace(&mut self.image, ImageBuffer::new(w * 2, h * 2));
            for ix in range(0, w) {
                for iy in range(0, h) {
                    *self.image.get_pixel_mut(ix, iy) = old[(ix, iy)];
                }
            }

            /*
            let mut dest = SubImage::new(&mut self.image, 0, 0, w, h);
            for ((_, _, a), b) in dest.pixels_mut().zip(old.pixels()) {
                *a = *b;
            }
            */
        }

        let (x, y) = if self.position < size {
            (self.position, size)
        } else {
            (size, self.position - size)
        };

        self.position += 1;
        if self.position >= size * 2 + 1 {
            self.position = 0;
            self.completed_tiles_size += 1;
        }

        {
            let [x, y, w, h] = [x * uw, y * uh, uw, uh];
            for ix in range(0, w) {
                for iy in range(0, h) {
                    *self.image.get_pixel_mut(ix + x, iy + y) = img[(ix, iy)];
                }
            }
        }

        /*
        let mut dest = SubImage::new(&mut self.image, x * uw, y * uh, uw, uh);
        for ((_, _, a), b) in dest.pixels_mut().zip(img.pixels()) {
            *a = *b;
        }
        */

        *match self.tile_positions.entry(name.to_string()) {
            Occupied(entry) => entry.into_mut(),
            Vacant(entry) => entry.insert((x * uw, y * uh))
        }
    }

    /// Finds the minimum alpha value in a given sub texture of the image.
    pub fn min_alpha(&mut self, rect: [u32; 4]) -> u8 {
        let [x, y, w, h] = rect;
        match self.min_alpha_cache.get(&(x, y, w, h)) {
            Some(alpha) => return *alpha,
            None => {}
        }

        let tile = SubImage::new(&mut self.image, x, y, w, h);
        let min_alpha = tile.pixels().map(|(_, _, p)| p[3])
            .min().unwrap_or(0);
        self.min_alpha_cache.insert((x, y, w, h), min_alpha);
        min_alpha
    }

    /// Returns the complete texture atlas as a texture.
    pub fn complete<D: Device>(self, d: &mut D) -> Texture {
        Texture::from_rgba8(self.image, d)
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder, clang_version};
use std::fs;
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::process::Command;

#[path="../src/options.rs"]
mod options;
use options::builder_from_flags;

fn compare_generated_header(header: &PathBuf,
                            builder: Builder)
                            -> Result<(), Error> {
    let file_name = try!(header.file_name()
        .ok_or(Error::new(ErrorKind::Other, "spawn_bindgen expects a file")));

    let mut expected = PathBuf::from(header);
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push("tests");
    expected.push(file_name);
    expected.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expected.is_file() {
        let file_name = expected.file_name().unwrap().to_owned();
        expected.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expected.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expected.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expected.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {},
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expected.push(format!("libclang-{}", version_str));
                }
            }
        }

        expected.push(file_name);

        if !expected.is_file() {
            panic!("missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                   header.display(),
                   expected.display());
        }
    }

    // We skip the generate() error here so we get a full diff below
    let output = match builder.generate() {
        Ok(bindings) => bindings.to_string(),
        Err(_) => "".to_string(),
    };

    let mut buffer = String::new();
    {
        if let Ok(expected_file) = fs::File::open(&expected) {
            try!(BufReader::new(expected_file).read_to_string(&mut buffer));
        }
    }

    if output == buffer {
        if !output.is_empty() {
            return Ok(());
        }
        return Err(Error::new(ErrorKind::Other,
                              "Something's gone really wrong!"));
    }

    println!("diff expected generated");
    println!("--- expected: {:?}", expected);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&buffer, &output) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expected_file = try!(fs::File::create(&expected));
        try!(expected_file.write_all(output.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags.into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
          !cfg!(target_os = "linux") {
              return Ok(None);
        }
    }

    // Windows platform has various different conventions than *nix platforms,
    // e.g. default enum underlying type, struct padding, mangling. Most tests
    // were written and checked on Linux and macOS, and thus they could fail on
    // Windows. We just make those tests targetting Linux instead as far as one
    // isn't annotated for a specific target.
    if cfg!(target_os = "windows") {
        if flags.iter().all(|flag| !flag.starts_with("--target=")) {
            if !flags.iter().any(|flag| flag == "--") {
                flags.push("--".into());
            }
            flags.push("--target=x86_64-unknown-linux".into());
        }
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str()
        .ok_or(Error::new(ErrorKind::Other, "Invalid header file name")));

    let prepend = ["bindgen",
                   "--with-derive-default",
                   header_str,
                   "--raw-line",
                   "",
                   "--raw-line",
                   "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
                   "--raw-line",
                   ""];

    let args = prepend.into_iter()
        .map(ToString::to_string)
        .chain(flags.into_iter());

    builder_from_flags(args)
        .map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let bindings = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .generate()
        .unwrap()
        .to_string();
    assert_eq!(bindings, "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
");
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/func_ptr.h"))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/enum.h"))
        .generate()
        .unwrap()
        .to_string();

    let expected = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"));

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
fn no_system_header_includes() {
    assert!(Command::new("./ci/no-includes.sh")
            .current_dir(env!("CARGO_MANIFEST_DIR"))
            .spawn()
            .expect("should spawn ./ci/no-includes.sh OK")
            .wait()
            .expect("should wait for ./ci/no-includes OK")
            .success());
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/cpp-empty-layout.hpp");

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(bindgen_ii.find(&arg_keyword).is_some(),
            "arg_keyword.hpp is in the preprocessed file");
    assert!(bindgen_ii.find(&empty_layout).is_some(),
            "cpp-empty-layout.hpp is in the preprocessed file");
}
<commit_msg>Skip no_system_header_includes test for Windows<commit_after>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder, clang_version};
use std::fs;
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;

#[path="../src/options.rs"]
mod options;
use options::builder_from_flags;

fn compare_generated_header(header: &PathBuf,
                            builder: Builder)
                            -> Result<(), Error> {
    let file_name = try!(header.file_name()
        .ok_or(Error::new(ErrorKind::Other, "spawn_bindgen expects a file")));

    let mut expected = PathBuf::from(header);
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push("tests");
    expected.push(file_name);
    expected.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expected.is_file() {
        let file_name = expected.file_name().unwrap().to_owned();
        expected.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expected.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expected.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expected.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {},
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expected.push(format!("libclang-{}", version_str));
                }
            }
        }

        expected.push(file_name);

        if !expected.is_file() {
            panic!("missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                   header.display(),
                   expected.display());
        }
    }

    // We skip the generate() error here so we get a full diff below
    let output = match builder.generate() {
        Ok(bindings) => bindings.to_string(),
        Err(_) => "".to_string(),
    };

    let mut buffer = String::new();
    {
        if let Ok(expected_file) = fs::File::open(&expected) {
            try!(BufReader::new(expected_file).read_to_string(&mut buffer));
        }
    }

    if output == buffer {
        if !output.is_empty() {
            return Ok(());
        }
        return Err(Error::new(ErrorKind::Other,
                              "Something's gone really wrong!"));
    }

    println!("diff expected generated");
    println!("--- expected: {:?}", expected);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&buffer, &output) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expected_file = try!(fs::File::create(&expected));
        try!(expected_file.write_all(output.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags.into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
          !cfg!(target_os = "linux") {
              return Ok(None);
        }
    }

    // Windows platform has various different conventions than *nix platforms,
    // e.g. default enum underlying type, struct padding, mangling. Most tests
    // were written and checked on Linux and macOS, and thus they could fail on
    // Windows. We just make those tests targetting Linux instead as far as one
    // isn't annotated for a specific target.
    if cfg!(target_os = "windows") {
        if flags.iter().all(|flag| !flag.starts_with("--target=")) {
            if !flags.iter().any(|flag| flag == "--") {
                flags.push("--".into());
            }
            flags.push("--target=x86_64-unknown-linux".into());
        }
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str()
        .ok_or(Error::new(ErrorKind::Other, "Invalid header file name")));

    let prepend = ["bindgen",
                   "--with-derive-default",
                   header_str,
                   "--raw-line",
                   "",
                   "--raw-line",
                   "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
                   "--raw-line",
                   ""];

    let args = prepend.into_iter()
        .map(ToString::to_string)
        .chain(flags.into_iter());

    builder_from_flags(args)
        .map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let bindings = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .generate()
        .unwrap()
        .to_string();
    assert_eq!(bindings, "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
");
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/func_ptr.h"))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/enum.h"))
        .generate()
        .unwrap()
        .to_string();

    let expected = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"));

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.
#[cfg(not(target_os = "windows"))]
fn no_system_header_includes() {
    use std::process::Command;
    assert!(Command::new("./ci/no-includes.sh")
            .current_dir(env!("CARGO_MANIFEST_DIR"))
            .spawn()
            .expect("should spawn ./ci/no-includes.sh OK")
            .wait()
            .expect("should wait for ./ci/no-includes OK")
            .success());
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/cpp-empty-layout.hpp");

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(bindgen_ii.find(&arg_keyword).is_some(),
            "arg_keyword.hpp is in the preprocessed file");
    assert!(bindgen_ii.find(&empty_layout).is_some(),
            "cpp-empty-layout.hpp is in the preprocessed file");
}
<|endoftext|>


<commit_before>use std::any::{Any, TypeId};
use std::collections::HashMap;

pub struct TypeMap {
    data: HashMap<TypeId, Box<Any>>
}

impl TypeMap {
    pub fn new() -> TypeMap {
        TypeMap { data: HashMap::new() }
    }

    pub fn find<T: Any>(&self) -> Option<&T> {
        self.data.get(&TypeId::of::<T>()).and_then(|a| a.downcast_ref())
    }

    pub fn find_mut<T: Any>(&mut self) -> Option<&mut T> {
        self.data.get_mut(&TypeId::of::<T>()).and_then(|a| a.downcast_mut())
    }

    pub fn insert<T: Any>(&mut self, val: T) -> bool {
        self.data.insert(TypeId::of::<T>(), Box::new(val) as Box<Any>).is_none()
    }

    pub fn remove<T: Any>(&mut self) -> bool {
        self.data.remove(&TypeId::of::<T>()).is_some()
    }

    pub fn contains<T: Any>(&self) -> bool {
        self.data.contains_key(&TypeId::of::<T>())
    }

    pub fn pop<T: Any>(&mut self) -> Option<T> {
        let data = match self.data.remove(&TypeId::of::<T>()) {
            Some(data) => data,
            None => return None,
        };
        Some(*data.downcast::<T>().ok().unwrap())
    }
}

#[cfg(test)]
mod tests {
    use super::TypeMap;

    #[test]
    fn smoke() {
        let mut m = TypeMap::new();
        assert!(m.insert(1));
        assert_eq!(*m.find::<i32>().unwrap(), 1);
        assert_eq!(*m.find_mut::<i32>().unwrap(), 1);
        assert!(!m.insert(2));
        assert!(m.remove::<i32>());
        assert!(!m.contains::<i32>());
        assert!(m.insert(4));
        assert_eq!(m.pop::<i32>().unwrap(), 4);
    }
}

<commit_msg>Drop Any bound<commit_after>use std::any::{Any, TypeId};
use std::collections::HashMap;

pub struct TypeMap {
    data: HashMap<TypeId, Box<Any>>
}

impl TypeMap {
    pub fn new() -> TypeMap {
        TypeMap { data: HashMap::new() }
    }

    pub fn find<T: 'static>(&self) -> Option<&T> {
        self.data.get(&TypeId::of::<T>()).and_then(|a| a.downcast_ref())
    }

    pub fn find_mut<T: 'static>(&mut self) -> Option<&mut T> {
        self.data.get_mut(&TypeId::of::<T>()).and_then(|a| a.downcast_mut())
    }

    pub fn insert<T: 'static>(&mut self, val: T) -> bool {
        self.data.insert(TypeId::of::<T>(), Box::new(val) as Box<Any>).is_none()
    }

    pub fn remove<T: 'static>(&mut self) -> bool {
        self.data.remove(&TypeId::of::<T>()).is_some()
    }

    pub fn contains<T: 'static>(&self) -> bool {
        self.data.contains_key(&TypeId::of::<T>())
    }

    pub fn pop<T: 'static>(&mut self) -> Option<T> {
        let data = match self.data.remove(&TypeId::of::<T>()) {
            Some(data) => data,
            None => return None,
        };
        Some(*data.downcast::<T>().ok().unwrap())
    }
}

#[cfg(test)]
mod tests {
    use super::TypeMap;

    #[test]
    fn smoke() {
        let mut m = TypeMap::new();
        assert!(m.insert(1));
        assert_eq!(*m.find::<i32>().unwrap(), 1);
        assert_eq!(*m.find_mut::<i32>().unwrap(), 1);
        assert!(!m.insert(2));
        assert!(m.remove::<i32>());
        assert!(!m.contains::<i32>());
        assert!(m.insert(4));
        assert_eq!(m.pop::<i32>().unwrap(), 4);
    }
}

<|endoftext|>


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

use conduit::{Request, Response};
use conduit_router::RequestParams;
use pg::GenericConnection;
use pg::rows::Row;
use pg::types::Slice;
use rustc_serialize::json;
use semver;
use time::Duration;
use time::Timespec;
use url;

use {Model, Crate, User};
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency, Kind};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use upload;
use user::RequestUser;
use owner::{rights, Rights};
use util::{RequestUtils, CargoResult, ChainError, internal, human};

#[derive(Clone)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

pub enum Author {
    User(User),
    Name(String),
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableVersion {
    pub id: i32,
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub links: VersionLinks,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

impl Version {
    pub fn find_by_num(conn: &GenericConnection,
                       crate_id: i32,
                       num: &semver::Version)
                       -> CargoResult<Option<Version>> {
        let num = num.to_string();
        let stmt = try!(conn.prepare("SELECT * FROM versions \
                                      WHERE crate_id = $1 AND num = $2"));
        let mut rows = try!(stmt.query(&[&crate_id, &num])).into_iter();
        Ok(rows.next().map(|r| Model::from_row(&r)))
    }

    pub fn insert(conn: &GenericConnection,
                  crate_id: i32,
                  num: &semver::Version,
                  features: &HashMap<String, Vec<String>>,
                  authors: &[String])
                  -> CargoResult<Version> {
        let num = num.to_string();
        let features = json::encode(features).unwrap();
        let stmt = try!(conn.prepare("INSERT INTO versions \
                                      (crate_id, num, updated_at, \
                                       created_at, downloads, features) \
                                      VALUES ($1, $2, $3, $3, 0, $4) \
                                      RETURNING *"));
        let now = ::now();
        let rows = try!(stmt.query(&[&crate_id, &num, &now, &features]));
        let ret: Version = Model::from_row(&try!(rows.iter().next().chain_error(|| {
            internal("no version returned")
        })));
        for author in authors.iter() {
            try!(ret.add_author(conn, &author));
        }
        Ok(ret)
    }

    pub fn valid(version: &str) -> bool {
        semver::Version::parse(version).is_ok()
    }

    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version { id, crate_id: _, num, updated_at, created_at,
                      downloads, features, yanked } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies",
                                      crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads",
                                           crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Add a dependency to this version, returning both the dependency and the
    /// crate that the dependency points to
    pub fn add_dependency(&mut self,
                          conn: &GenericConnection,
                          dep: &upload::CrateDependency)
                          -> CargoResult<(Dependency, Crate)> {
        let name = &dep.name;
        let krate = try!(Crate::find_by_name(conn, name).map_err(|_| {
            human(format!("no known crate named `{}`", &**name))
        }));
        if dep.version_req.0 == semver::VersionReq::parse("*").unwrap() {
            return Err(human(format!("wildcard (`*`) dependency constraints are not allowed \
                                      on crates.io")));
        }
        let features: Vec<String> = dep.features.iter().map(|s| {
            s[..].to_string()
        }).collect();
        let dep = try!(Dependency::insert(conn, self.id, krate.id,
                                          &*dep.version_req,
                                          dep.kind.unwrap_or(Kind::Normal),
                                          dep.optional,
                                          dep.default_features,
                                          &features,
                                          &dep.target));
        Ok((dep, krate))
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &GenericConnection)
                        -> CargoResult<Vec<(Dependency, String)>> {
        let stmt = try!(conn.prepare("SELECT dependencies.*,
                                             crates.name AS crate_name
                                      FROM dependencies
                                      LEFT JOIN crates
                                        ON crates.id = dependencies.crate_id
                                      WHERE dependencies.version_id = $1"));
        Ok(try!(stmt.query(&[&self.id])).into_iter().map(|r| {
            (Model::from_row(&r), r.get("crate_name"))
        }).collect())
    }

    pub fn authors(&self, conn: &GenericConnection) -> CargoResult<Vec<Author>> {
        let stmt = try!(conn.prepare("SELECT * FROM version_authors
                                       WHERE version_id = $1"));
        let rows = try!(stmt.query(&[&self.id]));
        rows.into_iter().map(|row| {
            let user_id: Option<i32> = row.get("user_id");
            let name: String = row.get("name");
            Ok(match user_id {
                Some(id) => Author::User(try!(User::find(conn, id))),
                None => Author::Name(name),
            })
        }).collect()
    }

    pub fn add_author(&self,
                      conn: &GenericConnection,
                      name: &str) -> CargoResult<()> {
        println!("add author: {}", name);
        // TODO: at least try to link `name` to a pre-existing user
        try!(conn.execute("INSERT INTO version_authors (version_id, name)
                           VALUES ($1, $2)", &[&self.id, &name]));
        Ok(())
    }

    pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> {
        try!(conn.execute("UPDATE versions SET yanked = $1 WHERE id = $2",
                          &[&yanked, &self.id]));
        Ok(())
    }
}

impl Model for Version {
    fn from_row(row: &Row) -> Version {
        let num: String = row.get("num");
        let features: Option<String> = row.get("features");
        let features = features.map(|s| {
            json::decode(&s).unwrap()
        }).unwrap_or_else(|| HashMap::new());
        Version {
            id: row.get("id"),
            crate_id: row.get("crate_id"),
            num: semver::Version::parse(&num).unwrap(),
            updated_at: row.get("updated_at"),
            created_at: row.get("created_at"),
            downloads: row.get("downloads"),
            features: features,
            yanked: row.get("yanked"),
        }
    }
    fn table_name(_: Option<Version>) -> &'static str { "versions" }
}

/// Handles the `GET /versions` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    let conn = try!(req.tx());

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("")
                                               .as_bytes());
    let ids = query.iter().filter_map(|&(ref a, ref b)| {
        if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        }
    }).collect::<Vec<i32>>();

    // Load all versions
    //
    // TODO: can rust-postgres do this for us?
    let mut versions = Vec::new();
    if ids.len() > 0 {
        let stmt = try!(conn.prepare("\
            SELECT versions.*, crates.name AS crate_name
              FROM versions
            LEFT JOIN crates ON crates.id = versions.crate_id
            WHERE versions.id = ANY($1)
        "));
        for row in try!(stmt.query(&[&Slice(&ids)])) {
            let v: Version = Model::from_row(&row);
            let crate_name: String = row.get("crate_name");
            versions.push(v.encodable(&crate_name));
        }
    }

    #[derive(RustcEncodable)]
    struct R { versions: Vec<EncodableVersion> }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => try!(version_and_crate(req)),
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = try!(req.tx());
            let version = try!(Version::find(&*conn, id));
            let krate = try!(Crate::find(&*conn, version.crate_id));
            (version, krate)
        }
    };

    #[derive(RustcEncodable)]
    struct R { version: EncodableVersion }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    let semver = try!(semver::Version::parse(semver).map_err(|_| {
        human(format!("invalid semver: {}", semver))
    }));
    let tx = try!(req.tx());
    let krate = try!(Crate::find_by_name(tx, crate_name));
    let version = try!(Version::find_by_num(tx, krate.id, &semver));
    let version = try!(version.chain_error(|| {
        human(format!("crate `{}` does not have a version `{}`",
                      crate_name, semver))
    }));
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = try!(version_and_crate(req));
    let tx = try!(req.tx());
    let deps = try!(version.dependencies(tx));
    let deps = deps.into_iter().map(|(dep, crate_name)| {
        dep.encodable(&crate_name)
    }).collect();

    #[derive(RustcEncodable)]
    struct R { dependencies: Vec<EncodableDependency> }
    Ok(req.json(&R{ dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = try!(version_and_crate(req));

    let tx = try!(req.tx());
    let cutoff_date = ::now() + Duration::days(-90);
    let stmt = try!(tx.prepare("SELECT * FROM version_downloads
                                WHERE date > $1 AND version_id = $2
                                ORDER BY date ASC"));
    let mut downloads = Vec::new();
    for row in try!(stmt.query(&[&cutoff_date, &version.id])) {
        let download: VersionDownload = Model::from_row(&row);
        downloads.push(download.encodable());
    }

    #[derive(RustcEncodable)]
    struct R { version_downloads: Vec<EncodableVersionDownload> }
    Ok(req.json(&R{ version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = try!(version_and_crate(req));
    let tx = try!(req.tx());
    let (mut users, mut names) = (Vec::new(), Vec::new());
    for author in try!(version.authors(tx)).into_iter() {
        match author {
            Author::User(u) => users.push(u.encodable()),
            Author::Name(n) => names.push(n),
        }
    }

    #[derive(RustcEncodable)]
    struct R { users: Vec<::user::EncodableUser>, meta: Meta }
    #[derive(RustcEncodable)]
    struct Meta { names: Vec<String> }
    Ok(req.json(&R{ users: users, meta: Meta { names: names } }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = try!(version_and_crate(req));
    let user = try!(req.user());
    let tx = try!(req.tx());
    let owners = try!(krate.owners(tx));
    if try!(rights(req.app(), &owners, &user)) < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"))
    }

    if version.yanked != yanked {
        try!(version.yank(tx, yanked));
        try!(git::yank(&**req.app(), &krate.name, &version.num, yanked));
    }

    #[derive(RustcEncodable)]
    struct R { ok: bool }
    Ok(req.json(&R{ ok: true }))
}
<commit_msg>Include FAQ link in wildcard error<commit_after>use std::collections::HashMap;

use conduit::{Request, Response};
use conduit_router::RequestParams;
use pg::GenericConnection;
use pg::rows::Row;
use pg::types::Slice;
use rustc_serialize::json;
use semver;
use time::Duration;
use time::Timespec;
use url;

use {Model, Crate, User};
use app::RequestApp;
use db::RequestTransaction;
use dependency::{Dependency, EncodableDependency, Kind};
use download::{VersionDownload, EncodableVersionDownload};
use git;
use upload;
use user::RequestUser;
use owner::{rights, Rights};
use util::{RequestUtils, CargoResult, ChainError, internal, human};

#[derive(Clone)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: Timespec,
    pub created_at: Timespec,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

pub enum Author {
    User(User),
    Name(String),
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableVersion {
    pub id: i32,
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub updated_at: String,
    pub created_at: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub links: VersionLinks,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct VersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

impl Version {
    pub fn find_by_num(conn: &GenericConnection,
                       crate_id: i32,
                       num: &semver::Version)
                       -> CargoResult<Option<Version>> {
        let num = num.to_string();
        let stmt = try!(conn.prepare("SELECT * FROM versions \
                                      WHERE crate_id = $1 AND num = $2"));
        let mut rows = try!(stmt.query(&[&crate_id, &num])).into_iter();
        Ok(rows.next().map(|r| Model::from_row(&r)))
    }

    pub fn insert(conn: &GenericConnection,
                  crate_id: i32,
                  num: &semver::Version,
                  features: &HashMap<String, Vec<String>>,
                  authors: &[String])
                  -> CargoResult<Version> {
        let num = num.to_string();
        let features = json::encode(features).unwrap();
        let stmt = try!(conn.prepare("INSERT INTO versions \
                                      (crate_id, num, updated_at, \
                                       created_at, downloads, features) \
                                      VALUES ($1, $2, $3, $3, 0, $4) \
                                      RETURNING *"));
        let now = ::now();
        let rows = try!(stmt.query(&[&crate_id, &num, &now, &features]));
        let ret: Version = Model::from_row(&try!(rows.iter().next().chain_error(|| {
            internal("no version returned")
        })));
        for author in authors.iter() {
            try!(ret.add_author(conn, &author));
        }
        Ok(ret)
    }

    pub fn valid(version: &str) -> bool {
        semver::Version::parse(version).is_ok()
    }

    pub fn encodable(self, crate_name: &str) -> EncodableVersion {
        let Version { id, crate_id: _, num, updated_at, created_at,
                      downloads, features, yanked } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            num: num.clone(),
            id: id,
            krate: crate_name.to_string(),
            updated_at: ::encode_time(updated_at),
            created_at: ::encode_time(created_at),
            downloads: downloads,
            features: features,
            yanked: yanked,
            links: VersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies",
                                      crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads",
                                           crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
        }
    }

    /// Add a dependency to this version, returning both the dependency and the
    /// crate that the dependency points to
    pub fn add_dependency(&mut self,
                          conn: &GenericConnection,
                          dep: &upload::CrateDependency)
                          -> CargoResult<(Dependency, Crate)> {
        let name = &dep.name;
        let krate = try!(Crate::find_by_name(conn, name).map_err(|_| {
            human(format!("no known crate named `{}`", &**name))
        }));
        if dep.version_req.0 == semver::VersionReq::parse("*").unwrap() {
            return Err(human(format!("wildcard (`*`) dependency constraints are not allowed \
                                      on crates.io. See http://doc.crates.io/faq.html#can-\
                                      libraries-use--as-a-version-for-their-dependencies for more \
                                      information")));
        }
        let features: Vec<String> = dep.features.iter().map(|s| {
            s[..].to_string()
        }).collect();
        let dep = try!(Dependency::insert(conn, self.id, krate.id,
                                          &*dep.version_req,
                                          dep.kind.unwrap_or(Kind::Normal),
                                          dep.optional,
                                          dep.default_features,
                                          &features,
                                          &dep.target));
        Ok((dep, krate))
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &GenericConnection)
                        -> CargoResult<Vec<(Dependency, String)>> {
        let stmt = try!(conn.prepare("SELECT dependencies.*,
                                             crates.name AS crate_name
                                      FROM dependencies
                                      LEFT JOIN crates
                                        ON crates.id = dependencies.crate_id
                                      WHERE dependencies.version_id = $1"));
        Ok(try!(stmt.query(&[&self.id])).into_iter().map(|r| {
            (Model::from_row(&r), r.get("crate_name"))
        }).collect())
    }

    pub fn authors(&self, conn: &GenericConnection) -> CargoResult<Vec<Author>> {
        let stmt = try!(conn.prepare("SELECT * FROM version_authors
                                       WHERE version_id = $1"));
        let rows = try!(stmt.query(&[&self.id]));
        rows.into_iter().map(|row| {
            let user_id: Option<i32> = row.get("user_id");
            let name: String = row.get("name");
            Ok(match user_id {
                Some(id) => Author::User(try!(User::find(conn, id))),
                None => Author::Name(name),
            })
        }).collect()
    }

    pub fn add_author(&self,
                      conn: &GenericConnection,
                      name: &str) -> CargoResult<()> {
        println!("add author: {}", name);
        // TODO: at least try to link `name` to a pre-existing user
        try!(conn.execute("INSERT INTO version_authors (version_id, name)
                           VALUES ($1, $2)", &[&self.id, &name]));
        Ok(())
    }

    pub fn yank(&self, conn: &GenericConnection, yanked: bool) -> CargoResult<()> {
        try!(conn.execute("UPDATE versions SET yanked = $1 WHERE id = $2",
                          &[&yanked, &self.id]));
        Ok(())
    }
}

impl Model for Version {
    fn from_row(row: &Row) -> Version {
        let num: String = row.get("num");
        let features: Option<String> = row.get("features");
        let features = features.map(|s| {
            json::decode(&s).unwrap()
        }).unwrap_or_else(|| HashMap::new());
        Version {
            id: row.get("id"),
            crate_id: row.get("crate_id"),
            num: semver::Version::parse(&num).unwrap(),
            updated_at: row.get("updated_at"),
            created_at: row.get("created_at"),
            downloads: row.get("downloads"),
            features: features,
            yanked: row.get("yanked"),
        }
    }
    fn table_name(_: Option<Version>) -> &'static str { "versions" }
}

/// Handles the `GET /versions` route.
pub fn index(req: &mut Request) -> CargoResult<Response> {
    let conn = try!(req.tx());

    // Extract all ids requested.
    let query = url::form_urlencoded::parse(req.query_string().unwrap_or("")
                                               .as_bytes());
    let ids = query.iter().filter_map(|&(ref a, ref b)| {
        if *a == "ids[]" {
            b.parse().ok()
        } else {
            None
        }
    }).collect::<Vec<i32>>();

    // Load all versions
    //
    // TODO: can rust-postgres do this for us?
    let mut versions = Vec::new();
    if ids.len() > 0 {
        let stmt = try!(conn.prepare("\
            SELECT versions.*, crates.name AS crate_name
              FROM versions
            LEFT JOIN crates ON crates.id = versions.crate_id
            WHERE versions.id = ANY($1)
        "));
        for row in try!(stmt.query(&[&Slice(&ids)])) {
            let v: Version = Model::from_row(&row);
            let crate_name: String = row.get("crate_name");
            versions.push(v.encodable(&crate_name));
        }
    }

    #[derive(RustcEncodable)]
    struct R { versions: Vec<EncodableVersion> }
    Ok(req.json(&R { versions: versions }))
}

/// Handles the `GET /versions/:version_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
    let (version, krate) = match req.params().find("crate_id") {
        Some(..) => try!(version_and_crate(req)),
        None => {
            let id = &req.params()["version_id"];
            let id = id.parse().unwrap_or(0);
            let conn = try!(req.tx());
            let version = try!(Version::find(&*conn, id));
            let krate = try!(Crate::find(&*conn, version.crate_id));
            (version, krate)
        }
    };

    #[derive(RustcEncodable)]
    struct R { version: EncodableVersion }
    Ok(req.json(&R { version: version.encodable(&krate.name) }))
}

fn version_and_crate(req: &mut Request) -> CargoResult<(Version, Crate)> {
    let crate_name = &req.params()["crate_id"];
    let semver = &req.params()["version"];
    let semver = try!(semver::Version::parse(semver).map_err(|_| {
        human(format!("invalid semver: {}", semver))
    }));
    let tx = try!(req.tx());
    let krate = try!(Crate::find_by_name(tx, crate_name));
    let version = try!(Version::find_by_num(tx, krate.id, &semver));
    let version = try!(version.chain_error(|| {
        human(format!("crate `{}` does not have a version `{}`",
                      crate_name, semver))
    }));
    Ok((version, krate))
}

/// Handles the `GET /crates/:crate_id/:version/dependencies` route.
pub fn dependencies(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = try!(version_and_crate(req));
    let tx = try!(req.tx());
    let deps = try!(version.dependencies(tx));
    let deps = deps.into_iter().map(|(dep, crate_name)| {
        dep.encodable(&crate_name)
    }).collect();

    #[derive(RustcEncodable)]
    struct R { dependencies: Vec<EncodableDependency> }
    Ok(req.json(&R{ dependencies: deps }))
}

/// Handles the `GET /crates/:crate_id/:version/downloads` route.
pub fn downloads(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = try!(version_and_crate(req));

    let tx = try!(req.tx());
    let cutoff_date = ::now() + Duration::days(-90);
    let stmt = try!(tx.prepare("SELECT * FROM version_downloads
                                WHERE date > $1 AND version_id = $2
                                ORDER BY date ASC"));
    let mut downloads = Vec::new();
    for row in try!(stmt.query(&[&cutoff_date, &version.id])) {
        let download: VersionDownload = Model::from_row(&row);
        downloads.push(download.encodable());
    }

    #[derive(RustcEncodable)]
    struct R { version_downloads: Vec<EncodableVersionDownload> }
    Ok(req.json(&R{ version_downloads: downloads }))
}

/// Handles the `GET /crates/:crate_id/:version/authors` route.
pub fn authors(req: &mut Request) -> CargoResult<Response> {
    let (version, _) = try!(version_and_crate(req));
    let tx = try!(req.tx());
    let (mut users, mut names) = (Vec::new(), Vec::new());
    for author in try!(version.authors(tx)).into_iter() {
        match author {
            Author::User(u) => users.push(u.encodable()),
            Author::Name(n) => names.push(n),
        }
    }

    #[derive(RustcEncodable)]
    struct R { users: Vec<::user::EncodableUser>, meta: Meta }
    #[derive(RustcEncodable)]
    struct Meta { names: Vec<String> }
    Ok(req.json(&R{ users: users, meta: Meta { names: names } }))
}

/// Handles the `DELETE /crates/:crate_id/:version/yank` route.
pub fn yank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, true)
}

/// Handles the `PUT /crates/:crate_id/:version/unyank` route.
pub fn unyank(req: &mut Request) -> CargoResult<Response> {
    modify_yank(req, false)
}

fn modify_yank(req: &mut Request, yanked: bool) -> CargoResult<Response> {
    let (version, krate) = try!(version_and_crate(req));
    let user = try!(req.user());
    let tx = try!(req.tx());
    let owners = try!(krate.owners(tx));
    if try!(rights(req.app(), &owners, &user)) < Rights::Publish {
        return Err(human("must already be an owner to yank or unyank"))
    }

    if version.yanked != yanked {
        try!(version.yank(tx, yanked));
        try!(git::yank(&**req.app(), &krate.name, &version.num, yanked));
    }

    #[derive(RustcEncodable)]
    struct R { ok: bool }
    Ok(req.json(&R{ ok: true }))
}
<|endoftext|>


<commit_before>use std::env;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::io::Read;

use reqwest;
use serde_json;

use bot;
use update::Update;
use error::Result;

const BASE_URL: &'static str = "https://api.telegram.org/bot";

#[derive(Debug)]
pub struct Updater {
	token: String,
	bot: bot::Bot,
	client: reqwest::Client,
}

impl Updater {
	/// Creates a new Updater struct.
    pub fn new(token: Option<String>) -> Result<Updater> {
        let token = token.or_else(|| env::var("TELEGRAM_BOT_TOKEN").ok())
                .expect("You should pass in a token to new or set TELEGRAM_BOT_TOKEN");

        let bot_url = [BASE_URL, &token].concat();
		let bot = bot::Bot::new(bot_url)?;
		let client = reqwest::Client::new()?;

		Ok(Updater {
			token: token,
			bot: bot,
            client: client,
		})
    }

    pub fn start_polling(&self) {
        unimplemented!();
    }

    /// Function to get all the messages for the bot.
    pub fn get_updates<E>(&self) -> Result<Update> {
    	let path = ["getUpdates"];
    	let url = ::construct_api_url(&self.bot.bot_url, &path);
    	let params = [("timeout", 30)];
    	let mut data = self.client.get(&url).form(&params).send()?;
    	let rjson: serde_json::Value = data.json()?;

		Ok(Update::new())
    }
}
<commit_msg>Took out some unnecessary code.<commit_after>use std::env;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::io::Read;

use reqwest;
use serde_json;

use bot;
use update::Update;
use error::Result;

const BASE_URL: &'static str = "https://api.telegram.org/bot";

#[derive(Debug)]
pub struct Updater {
	token: String,
	bot: bot::Bot,
	client: reqwest::Client,
}

impl Updater {
	/// Creates a new Updater struct.
    pub fn new(token: Option<String>) -> Result<Updater> {
        let token = token.or_else(|| env::var("TELEGRAM_BOT_TOKEN").ok())
                .expect("You should pass in a token to new or set TELEGRAM_BOT_TOKEN");

        let bot_url = [BASE_URL, &token].concat();
		let bot = bot::Bot::new(bot_url)?;
		let client = reqwest::Client::new()?;

		Ok(Updater {
			token: token,
			bot: bot,
            client: client,
		})
    }

    pub fn start_polling(&self) {
        unimplemented!();
    }

    fn start_polling_thread(&self) {
        loop {
            unimplemented!();
        }
    }
}
<|endoftext|>


<commit_before>//! Parses "term" queries

use rustc_serialize::json::Json;
use abra::{Term, Query, TermMatcher, TermScorer};

use query_parser::{QueryParseContext, QueryParseError};
use query_parser::utils::parse_float;

pub fn parse(context: &QueryParseContext, json: &Json) -> Result<Query, QueryParseError> {
    let object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    let field_name = if object.len() == 1 {
        object.keys().collect::<Vec<_>>()[0]
    } else {
        return Err(QueryParseError::ExpectedSingleKey)
    };

    let object = object.get(field_name).unwrap();

    // Get configuration
    let mut term: Option<Term> = None;
    let mut boost = 1.0f64;

    match *object {
        Json::Object(ref inner_object) => {
            for (key, val) in inner_object.iter() {
                match key.as_ref() {
                    "value" => {
                        term = Term::from_json(val);

                        if term == None {
                            return Err(QueryParseError::InvalidValue);
                        }
                    }
                    "boost" => {
                        boost = try!(parse_float(val));
                    }
                    _ => return Err(QueryParseError::UnrecognisedKey(key.clone()))
                }
            }
        }
        _ => term = Term::from_json(object),
    }

    match term {
        Some(term) => {
            let mut query = Query::MatchTerm {
                field: field_name.clone(),
                term: term,
                matcher: TermMatcher::Exact,
                scorer: TermScorer::default(),
            };

            // Add boost
            query = Query::new_boost(query, boost);

            Ok(query)
        }
        None => Err(QueryParseError::ExpectedKey("value"))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;

    use abra::{Term, Query, TermMatcher, TermScorer};

    use query_parser::{QueryParseContext, QueryParseError};

    use super::parse;

    #[test]
    fn test_term_query() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": \"bar\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::String("bar".to_string()),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default(),
        }));
    }

    #[test]
    fn test_with_number() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": 123
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::U64(123),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default(),
        }));
    }

    #[test]
    fn test_simple_term_query() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": \"bar\"
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::String("bar".to_string()),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default(),
        }));
    }

    #[test]
    fn test_with_boost() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": \"bar\",
                \"boost\": 2.0
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Boost {
            query: Box::new(Query::MatchTerm {
                field: "foo".to_string(),
                term: Term::String("bar".to_string()),
                matcher: TermMatcher::Exact,
                scorer: TermScorer::default(),
            }),
            boost: 2.0f64,
        }));
    }

    #[test]
    fn test_with_boost_integer() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": \"bar\",
                \"boost\": 2
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::Boost {
            query: Box::new(Query::MatchTerm {
                field: "foo".to_string(),
                term: Term::String("bar".to_string()),
                matcher: TermMatcher::Exact,
                scorer: TermScorer::default(),
            }),
            boost: 2.0f64,
        }));
    }

    #[test]
    fn test_gives_error_for_incorrect_type() {
        // Array
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        [
            \"foo\"
        ]
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Integer
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        123
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Float
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        123.1234
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));
    }

    #[test]
    fn test_gives_error_for_incorrect_boost_type() {
        // String
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": \"2\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Array
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": [2]
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Object
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": {
                    \"value\": 2
                }
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));
    }

    #[test]
    fn test_gives_error_for_missing_value() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedKey("value")));
    }

    #[test]
    fn test_gives_error_for_extra_key() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\"
            },
            \"hello\": \"world\"
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedSingleKey));
    }

    #[test]
    fn test_gives_error_for_extra_inner_key() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"hello\": \"world\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::UnrecognisedKey("hello".to_string())));
    }
}
<commit_msg>Use new boosting method in term query<commit_after>//! Parses "term" queries

use rustc_serialize::json::Json;
use abra::{Term, Query, TermMatcher, TermScorer};

use query_parser::{QueryParseContext, QueryParseError};
use query_parser::utils::parse_float;

pub fn parse(context: &QueryParseContext, json: &Json) -> Result<Query, QueryParseError> {
    let object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    let field_name = if object.len() == 1 {
        object.keys().collect::<Vec<_>>()[0]
    } else {
        return Err(QueryParseError::ExpectedSingleKey)
    };

    let object = object.get(field_name).unwrap();

    // Get configuration
    let mut term: Option<Term> = None;
    let mut boost = 1.0f64;

    match *object {
        Json::Object(ref inner_object) => {
            for (key, val) in inner_object.iter() {
                match key.as_ref() {
                    "value" => {
                        term = Term::from_json(val);

                        if term == None {
                            return Err(QueryParseError::InvalidValue);
                        }
                    }
                    "boost" => {
                        boost = try!(parse_float(val));
                    }
                    _ => return Err(QueryParseError::UnrecognisedKey(key.clone()))
                }
            }
        }
        _ => term = Term::from_json(object),
    }

    match term {
        Some(term) => {
            let mut query = Query::MatchTerm {
                field: field_name.clone(),
                term: term,
                matcher: TermMatcher::Exact,
                scorer: TermScorer::default(),
            };

            // Add boost
            query.boost(boost);

            Ok(query)
        }
        None => Err(QueryParseError::ExpectedKey("value"))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;

    use abra::{Term, Query, TermMatcher, TermScorer};

    use query_parser::{QueryParseContext, QueryParseError};

    use super::parse;

    #[test]
    fn test_term_query() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": \"bar\"
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::String("bar".to_string()),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default(),
        }));
    }

    #[test]
    fn test_with_number() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": 123
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::U64(123),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default(),
        }));
    }

    #[test]
    fn test_simple_term_query() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": \"bar\"
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::String("bar".to_string()),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default(),
        }));
    }

    #[test]
    fn test_with_boost() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": \"bar\",
                \"boost\": 2.0
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::String("bar".to_string()),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default_with_boost(2.0f64),
        }));
    }

    #[test]
    fn test_with_boost_integer() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"value\": \"bar\",
                \"boost\": 2
            }
        }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchTerm {
            field: "foo".to_string(),
            term: Term::String("bar".to_string()),
            matcher: TermMatcher::Exact,
            scorer: TermScorer::default_with_boost(2.0f64),
        }));
    }

    #[test]
    fn test_gives_error_for_incorrect_type() {
        // Array
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        [
            \"foo\"
        ]
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Integer
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        123
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));

        // Float
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        123.1234
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedObject));
    }

    #[test]
    fn test_gives_error_for_incorrect_boost_type() {
        // String
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": \"2\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Array
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": [2]
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));

        // Object
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"boost\": {
                    \"value\": 2
                }
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedFloat));
    }

    #[test]
    fn test_gives_error_for_missing_value() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedKey("value")));
    }

    #[test]
    fn test_gives_error_for_extra_key() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\"
            },
            \"hello\": \"world\"
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::ExpectedSingleKey));
    }

    #[test]
    fn test_gives_error_for_extra_inner_key() {
        let query = parse(&QueryParseContext::new(), &Json::from_str("
        {
            \"foo\": {
                \"query\": \"bar\",
                \"hello\": \"world\"
            }
        }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::UnrecognisedKey("hello".to_string())));
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::ffi::{OsString, OsStr};

pub fn run() {
    println!("********* API Design Examples (AsRef<> for String-like parameters) *********");

    // If something is commented out, it won't compile.
    string_examples();
    path_examples();
}

fn string_by_value(s: String) {
}

fn string_by_ref(s: &String) {
}

fn string_slice(s: &str) {
    // This can be called with a String (using &) and a &str.
}

fn string_borrow_or_move<T: AsRef<str>>(s: T) {
    // This can be called with a String (using &) and a &str PLUS a move of a String.
    // But no Path types.

    // By declaring that we accept AsRef<str>, we are saying that we will accept anything
    // that can be converted to &str. Sometimes this conversion is free, sometimes it isn't.
    // The conversion is guaranteed to work (not panic).
    // We have to make that conversion like this (s is now of type &str):

    let s = s.as_ref();

    // The original 's' parameter has no useful methods, other than as_ref().
    // So we have to call it, and we have to call it manually, as shown above.
}

fn string_examples() {
    let s = "A String".to_string();
    string_by_value(s);
    // string_by_value(&s);
    // string_by_value("hello");

    let s = "A String".to_string();
    // string_by_ref(s);
    string_by_ref(&s);
    // string_by_ref("hello");

    let s = "A String".to_string();
    //string_slice(s);
    string_slice(&s);
    string_slice("hello");

    let s = "A String".to_string();
    string_borrow_or_move(&s);
    string_borrow_or_move("hello");
    string_borrow_or_move(s);
    //string_borrow_or_move(s);
}

fn path_or_string<T: AsRef<Path>>(s : T) {
    // x is of type &Path.
    let x = s.as_ref();
}

fn path_examples() {
    let s = "A String".to_string();
    let p = PathBuf::from("A PathBuf");
    let p_temp = PathBuf::from("A Path");
    let p2 = p_temp.as_path();

    // None of the string functions will accept a PathBuf.
    //string_by_value(p);
    //string_by_ref(&p);
    //string_slice(p);
    //string_slice(&p);

    //string_borrow_or_move(p);
    //string_borrow_or_move(&p);

    // So we can call this with &str, &String, &Path and &PathBuf (all borrows)
    // or moves of String or PathBuf.
    path_or_string("hello");
    path_or_string(&p);
    path_or_string(p);
    path_or_string(&s);
    path_or_string(s);
    path_or_string(&p2);
    path_or_string(p2);

    // If you look at https://doc.rust-lang.org/std/convert/trait.AsRef.html
    // You can see everything that can be converted to, say, &Path. It includes
    // things like OsStr, OsString and Cow<'a, OsStr>. One more demo.

    let c = OsString::from("heee");
    path_or_string(&c);
}
<commit_msg>Rust: add an AsRef example for slices.<commit_after>use std::path::{Path, PathBuf};
use std::ffi::{OsString, OsStr};

pub fn run() {
    println!("********* API Design Examples (AsRef<> for String-like parameters) *********");

    // If something is commented out, it won't compile.
    string_examples();
    path_examples();
    array_example();
}

fn string_by_value(s: String) {
}

fn string_by_ref(s: &String) {
}

fn string_slice(s: &str) {
    // This can be called with a String (using &) and a &str.
}

fn string_borrow_or_move<T: AsRef<str>>(s: T) {
    // This can be called with a String (using &) and a &str PLUS a move of a String.
    // But no Path types.

    // By declaring that we accept AsRef<str>, we are saying that we will accept anything
    // that can be converted to &str. Sometimes this conversion is free, sometimes it isn't.
    // The conversion is guaranteed to work (not panic).
    // We have to make that conversion like this (s is now of type &str):

    let s = s.as_ref();

    // The original 's' parameter has no useful methods, other than as_ref().
    // So we have to call it, and we have to call it manually, as shown above.
}

fn string_examples() {
    let s = "A String".to_string();
    string_by_value(s);
    // string_by_value(&s);
    // string_by_value("hello");

    let s = "A String".to_string();
    // string_by_ref(s);
    string_by_ref(&s);
    // string_by_ref("hello");

    let s = "A String".to_string();
    //string_slice(s);
    string_slice(&s);
    string_slice("hello");

    let s = "A String".to_string();
    string_borrow_or_move(&s);
    string_borrow_or_move("hello");
    string_borrow_or_move(s);
    //string_borrow_or_move(s);
}

fn path_or_string<T: AsRef<Path>>(s : T) {
    // x is of type &Path.
    let x = s.as_ref();
}

fn path_examples() {
    let s = "A String".to_string();
    let p = PathBuf::from("A PathBuf");
    let p_temp = PathBuf::from("A Path");
    let p2 = p_temp.as_path();

    // None of the string functions will accept a PathBuf.
    //string_by_value(p);
    //string_by_ref(&p);
    //string_slice(p);
    //string_slice(&p);

    //string_borrow_or_move(p);
    //string_borrow_or_move(&p);

    // So we can call this with &str, &String, &Path and &PathBuf (all borrows)
    // or moves of String or PathBuf.
    path_or_string("hello");
    path_or_string(&p);
    path_or_string(p);
    path_or_string(&s);
    path_or_string(s);
    path_or_string(&p2);
    path_or_string(p2);

    // If you look at https://doc.rust-lang.org/std/convert/trait.AsRef.html
    // You can see everything that can be converted to, say, &Path. It includes
    // things like OsStr, OsString and Cow<'a, OsStr>. One more demo.

    let c = OsString::from("heee");
    path_or_string(&c);
}

fn array_of_things<T: AsRef<str>>(values: &[T]) {
    for val in values {
        // v is of type &str.
        let v = val.as_ref();
    }
}

fn array_example() {
    let v_of_str = vec!["Hello", "world"];
    array_of_things(&v_of_str);

    let v_of_strings = vec!["Hello".to_string(), "world".to_string()];
    array_of_things(&v_of_strings);
}<|endoftext|>


<commit_before>use std::io::Read;

use nom::bits::complete::tag;
use nom::bits::complete::take;
use nom::branch::alt;
use nom::combinator::map;
use nom::multi::count;
use nom::sequence::preceded;
use nom::sequence::tuple;
use nom::IResult;

type Input<'a> = (&'a [u8], usize);

#[derive(Debug, Eq, PartialEq)]
enum Contents {
    Literal(Vec<u8>),
    Operator(u8, Vec<Packet>),
}

#[derive(Debug, Eq, PartialEq)]
struct Packet {
    version: u8,
    contents: Contents,
}

impl Packet {
    pub fn version_sum(&self) -> u32 {
        match &self.contents {
            Contents::Literal(_) => self.version as u32,
            Contents::Operator(_, sub_packets) => {
                self.version as u32 + sub_packets.iter().map(Packet::version_sum).sum::<u32>()
            }
        }
    }

    pub fn value(&self) -> u64 {
        match &self.contents {
            Contents::Literal(chunks) => chunks
                .iter()
                .fold(0, |acc, &chunk| (acc << 4) | (chunk as u64)),
            Contents::Operator(0, sub_packets) => sub_packets.iter().map(Packet::value).sum(),
            Contents::Operator(1, sub_packets) => sub_packets.iter().map(Packet::value).product(),
            Contents::Operator(2, sub_packets) => {
                sub_packets.iter().map(Packet::value).min().unwrap()
            }
            Contents::Operator(3, sub_packets) => {
                sub_packets.iter().map(Packet::value).max().unwrap()
            }
            Contents::Operator(5, sub_packets) => {
                (sub_packets[0].value() > sub_packets[1].value()) as u64
            }
            Contents::Operator(6, sub_packets) => {
                (sub_packets[0].value() < sub_packets[1].value()) as u64
            }
            Contents::Operator(7, sub_packets) => {
                (sub_packets[0].value() == sub_packets[1].value()) as u64
            }
            unknown => panic!("unknown packet {:?}", unknown),
        }
    }
}

fn parse_literal(mut input: Input) -> IResult<Input, (usize, Contents)> {
    let mut contents = Vec::new();

    loop {
        let (new_input, result) = take::<_, u8, usize, _>(5)(input)?;
        input = new_input;

        contents.push(result & 0xF);

        if (result & 0x10) == 0 {
            let len = 5 * contents.len();
            let contents = Contents::Literal(contents);

            return Ok((input, (len, contents)));
        }
    }
}

fn parse_operator_len(input: Input) -> IResult<Input, (usize, Vec<Packet>)> {
    const SIZE_LEN: usize = 15;

    let (mut input, to_read) = take(SIZE_LEN)(input)?;

    let mut read = 0;
    let mut packets = Vec::new();

    while read < to_read {
        let (new_input, (len, packet)) = parse_packet(input)?;
        input = new_input;
        read += len;
        packets.push(packet);
    }

    Ok((input, (to_read + SIZE_LEN, packets)))
}

fn parse_operator_count(input: Input) -> IResult<Input, (usize, Vec<Packet>)> {
    const SIZE_LEN: usize = 11;

    let (input, to_read) = take::<_, usize, _, _>(SIZE_LEN)(input)?;

    let (input, packets) = count(parse_packet, to_read)(input)?;

    let read_total = SIZE_LEN + packets.iter().map(|(len, _)| *len).sum::<usize>();

    Ok((
        input,
        (
            read_total,
            packets.into_iter().map(|(_, packet)| packet).collect(),
        ),
    ))
}

fn parse_packet(input: Input) -> IResult<Input, (usize, Packet)> {
    let parse_literal_packet = map(
        tuple((take(3usize), preceded(tag(4u8, 3usize), parse_literal))),
        |(version, (len, contents))| (len + 6, Packet { version, contents }),
    );

    let parse_operator_len_packet = map(
        tuple((
            take(3usize),
            take(3usize),
            preceded(tag(0u8, 1usize), parse_operator_len),
        )),
        |(version, operator, (len, contents))| {
            (
                len + 7,
                Packet {
                    version,
                    contents: Contents::Operator(operator, contents),
                },
            )
        },
    );

    let parse_operator_count_packet = map(
        tuple((
            take(3usize),
            take(3usize),
            preceded(tag(1u8, 1usize), parse_operator_count),
        )),
        |(version, operator, (len, contents))| {
            (
                len + 7,
                Packet {
                    version,
                    contents: Contents::Operator(operator, contents),
                },
            )
        },
    );

    alt((
        parse_literal_packet,
        parse_operator_len_packet,
        parse_operator_count_packet,
    ))(input)
}

fn convert_hex(hex: &[u8]) -> Vec<u8> {
    fn val(c: u8) -> u8 {
        match c {
            b'A'..=b'F' => c - b'A' + 10,
            b'0'..=b'9' => c - b'0',
            _ => panic!("Invalid hex digit {}", c),
        }
    }

    let mut binary = Vec::with_capacity(hex.len() / 2);

    binary.extend(
        hex.chunks_exact(2)
            .map(|chunk| (val(chunk[0]) << 4) | val(chunk[1])),
    );

    binary
}

pub fn part1(input: &mut dyn Read) -> String {
    let mut buffer = Vec::new();
    input.read_to_end(&mut buffer).unwrap();

    let binary_data = convert_hex(&buffer);
    let (_, (_, packet)) = parse_packet((&binary_data, 0)).unwrap();

    packet.version_sum().to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let mut buffer = Vec::new();
    input.read_to_end(&mut buffer).unwrap();

    let binary_data = convert_hex(&buffer);
    let (_, (_, packet)) = parse_packet((&binary_data, 0)).unwrap();

    packet.value().to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[&[u8]] = &[
        &*b"8A004A801A8002F478",
        &*b"620080001611562C8802118E34",
        &*b"C0015000016115A2E0802F182340",
        &*b"A0016C880162017C3686B18A3D4780",
    ];

    #[test]
    fn sample_part1() {
        let answers = [16, 12, 23, 31];

        for (&sample, answer) in SAMPLE.into_iter().zip(answers) {
            test_implementation(part1, sample, answer);
        }
    }

    #[test]
    fn test_parse_literal() {
        let (_, (len, packet)) = parse_packet((&convert_hex(b"D2FE28"), 0)).unwrap();

        assert_eq!(len, 21);
        assert_eq!(
            packet,
            Packet {
                version: 6,
                contents: Contents::Literal(vec![7, 14, 5])
            }
        );
    }

    #[test]
    fn test_parse_operator_len() {
        let (_, (len, packet)) = parse_packet((&convert_hex(b"38006F45291200"), 0)).unwrap();

        assert_eq!(len, 22 + 27);
        assert_eq!(packet.version, 1);

        assert!(matches!(packet.contents, Contents::Operator(6, _)));
    }

    #[test]
    fn test_parse_operator_count() {
        let (_, (len, packet)) = parse_packet((&convert_hex(b"EE00D40C823060"), 0)).unwrap();

        assert_eq!(len, 7 + 11 + 33);
        assert_eq!(packet.version, 7);

        assert!(matches!(packet.contents, Contents::Operator(3, _)));
    }
}
<commit_msg>Avoid allocating and tracking bits manually<commit_after>use std::io::Read;

use nom::bits::complete::tag;
use nom::bits::complete::take;
use nom::branch::alt;
use nom::combinator::map;
use nom::multi::count;
use nom::sequence::preceded;
use nom::sequence::tuple;
use nom::IResult;

type Input<'a> = (&'a [u8], usize);

#[derive(Debug, Eq, PartialEq)]
enum Contents {
    Literal(u64),
    Operator(u8, Vec<Packet>),
}

#[derive(Debug, Eq, PartialEq)]
struct Packet {
    version: u8,
    contents: Contents,
}

fn capacity(input: Input) -> usize {
    8 * input.0.len() - input.1 as usize
}

impl Packet {
    pub fn version_sum(&self) -> u32 {
        match &self.contents {
            Contents::Literal(_) => self.version as u32,
            Contents::Operator(_, sub_packets) => {
                self.version as u32 + sub_packets.iter().map(Packet::version_sum).sum::<u32>()
            }
        }
    }

    pub fn value(&self) -> u64 {
        match &self.contents {
            Contents::Literal(val) => *val,
            Contents::Operator(0, sub_packets) => sub_packets.iter().map(Packet::value).sum(),
            Contents::Operator(1, sub_packets) => sub_packets.iter().map(Packet::value).product(),
            Contents::Operator(2, sub_packets) => {
                sub_packets.iter().map(Packet::value).min().unwrap()
            }
            Contents::Operator(3, sub_packets) => {
                sub_packets.iter().map(Packet::value).max().unwrap()
            }
            Contents::Operator(5, sub_packets) => {
                (sub_packets[0].value() > sub_packets[1].value()) as u64
            }
            Contents::Operator(6, sub_packets) => {
                (sub_packets[0].value() < sub_packets[1].value()) as u64
            }
            Contents::Operator(7, sub_packets) => {
                (sub_packets[0].value() == sub_packets[1].value()) as u64
            }
            unknown => panic!("unknown packet {:?}", unknown),
        }
    }
}

fn parse_literal(mut input: Input) -> IResult<Input, Contents> {
    let mut val = 0;

    loop {
        let (new_input, result) = take::<_, u8, usize, _>(5)(input)?;
        input = new_input;

        val = (val << 4) | (result as u64 & 0xF);

        if (result & 0x10) == 0 {
            return Ok((input, Contents::Literal(val)));
        }
    }
}

fn parse_operator_len(input: Input) -> IResult<Input, Vec<Packet>> {
    const SIZE_LEN: usize = 15;

    let (mut input, to_read) = take(SIZE_LEN)(input)?;

    let mut packets = Vec::new();

    let initial = capacity(input);

    while initial - capacity(input) < to_read {
        let (new_input, packet) = parse_packet(input)?;
        input = new_input;
        packets.push(packet);
    }

    Ok((input, packets))
}

fn parse_operator_count(input: Input) -> IResult<Input, Vec<Packet>> {
    const SIZE_LEN: usize = 11;

    let (input, to_read) = take::<_, usize, _, _>(SIZE_LEN)(input)?;

    count(parse_packet, to_read)(input)
}

fn parse_packet(input: Input) -> IResult<Input, Packet> {
    let parse_literal_packet = map(
        tuple((take(3usize), preceded(tag(4u8, 3usize), parse_literal))),
        |(version, contents)| Packet { version, contents },
    );

    let parse_operator_len_packet = map(
        tuple((
            take(3usize),
            take(3usize),
            preceded(tag(0u8, 1usize), parse_operator_len),
        )),
        |(version, operator, contents)| Packet {
            version,
            contents: Contents::Operator(operator, contents),
        },
    );

    let parse_operator_count_packet = map(
        tuple((
            take(3usize),
            take(3usize),
            preceded(tag(1u8, 1usize), parse_operator_count),
        )),
        |(version, operator, contents)| Packet {
            version,
            contents: Contents::Operator(operator, contents),
        },
    );

    alt((
        parse_literal_packet,
        parse_operator_len_packet,
        parse_operator_count_packet,
    ))(input)
}

fn convert_hex(hex: &[u8]) -> Vec<u8> {
    fn val(c: u8) -> u8 {
        match c {
            b'A'..=b'F' => c - b'A' + 10,
            b'0'..=b'9' => c - b'0',
            _ => panic!("Invalid hex digit {}", c),
        }
    }

    let mut binary = Vec::with_capacity(hex.len() / 2);

    binary.extend(
        hex.chunks_exact(2)
            .map(|chunk| (val(chunk[0]) << 4) | val(chunk[1])),
    );

    binary
}

pub fn part1(input: &mut dyn Read) -> String {
    let mut buffer = Vec::new();
    input.read_to_end(&mut buffer).unwrap();

    let binary_data = convert_hex(&buffer);
    let (_, packet) = parse_packet((&binary_data, 0)).unwrap();

    packet.version_sum().to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let mut buffer = Vec::new();
    input.read_to_end(&mut buffer).unwrap();

    let binary_data = convert_hex(&buffer);
    let (_, packet) = parse_packet((&binary_data, 0)).unwrap();

    packet.value().to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[&[u8]] = &[
        &*b"8A004A801A8002F478",
        &*b"620080001611562C8802118E34",
        &*b"C0015000016115A2E0802F182340",
        &*b"A0016C880162017C3686B18A3D4780",
    ];

    #[test]
    fn sample_part1() {
        let answers = [16, 12, 23, 31];

        for (&sample, answer) in SAMPLE.into_iter().zip(answers) {
            test_implementation(part1, sample, answer);
        }
    }

    #[test]
    fn test_parse_literal() {
        let (_, packet) = parse_packet((&convert_hex(b"D2FE28"), 0)).unwrap();

        assert_eq!(
            packet,
            Packet {
                version: 6,
                contents: Contents::Literal(2021)
            }
        );
    }

    #[test]
    fn test_parse_operator_len() {
        let (_, packet) = parse_packet((&convert_hex(b"38006F45291200"), 0)).unwrap();

        assert_eq!(packet.version, 1);

        assert!(matches!(packet.contents, Contents::Operator(6, _)));
    }

    #[test]
    fn test_parse_operator_count() {
        let (_, packet) = parse_packet((&convert_hex(b"EE00D40C823060"), 0)).unwrap();

        assert_eq!(packet.version, 7);

        assert!(matches!(packet.contents, Contents::Operator(3, _)));
    }
}
<|endoftext|>