<commit_before>/*
Copyright (c) 2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use std::collections::HashMap;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

/// Legal values for the direction of a port on a module
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub enum PortDirection {
    #[serde(rename = "input")]
    Input,
    #[serde(rename = "output")]
    Output,
    #[serde(rename = "inout")]
    InOut,
}

/// Special constant bit values
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub enum SpecialBit {
    /// Constant 0
    #[serde(rename = "0")]
    _0,
    /// Constant 1
    #[serde(rename = "1")]
    _1,
    /// Constant X (invalid)
    #[serde(rename = "x")]
    X,
    /// Constant Z (tri-state)
    #[serde(rename = "z")]
    Z,
}

/// A number representing a single bit of a wire
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
pub enum BitVal {
    /// An actual signal number
    N(usize),
    /// A special constant value
    S(SpecialBit)
}

/// The value of an attribute/parameter
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
pub enum AttributeVal {
    /// Numeric attribute value
    N(usize),
    /// String attribute value
    S(String),
}

/// Represents an entire .json file used by Yosys
#[derive(Serialize, Deserialize, Debug)]
pub struct Netlist {
    /// The program that created this file.
    #[serde(default)]
    pub creator: String,
    /// A map from module names to module objects contained in this .json file
    #[serde(default)]
    pub modules: HashMap<String, Module>,
}

/// Represents one module in the Yosys hierarchy
#[derive(Serialize, Deserialize, Debug)]
pub struct Module {
    /// Module attributes
    #[serde(default)]
    pub attributes: HashMap<String, AttributeVal>,
    /// Module ports (interfaces to other modules)
    #[serde(default)]
    pub ports: HashMap<String, Port>,
    /// Module cells (objects inside this module)
    #[serde(default)]
    pub cells: HashMap<String, Cell>,
    /// Module netnames (names of wires in this module)
    #[serde(default)]
    pub netnames: HashMap<String, Netname>,
}

/// Represents a port on a module
#[derive(Serialize, Deserialize, Debug)]
pub struct Port {
    /// Port direction
    pub direction: PortDirection,
    /// Bit value(s) representing the wire(s) connected to this port
    pub bits: Vec<BitVal>,
}

/// Represents a cell in a module
#[derive(Serialize, Deserialize, Debug)]
pub struct Cell {
    /// Indicates an internal/auto-generated name that starts with `$`
    #[serde(default)]
    pub hide_name: usize,
    /// Name of the type of this cell
    #[serde(rename="type")]
    pub cell_type: String,
    /// Parameters specified on this cell
    #[serde(default)]
    pub parameters: HashMap<String, AttributeVal>,
    /// Attributes specified on this cell
    #[serde(default)]
    pub attributes: HashMap<String, AttributeVal>,
    /// The direction of the ports on this cell
    #[serde(default)]
    pub port_directions: HashMap<String, String>,
    /// Bit value(s) representing the wire(s) connected to the inputs/outputs of this cell
    pub connections: HashMap<String, Vec<BitVal>>,
}

/// Represents the name of a net in a module
#[derive(Serialize, Deserialize, Debug)]
pub struct Netname {
    /// Indicates an internal/auto-generated name that starts with `$`
    #[serde(default)]
    pub hide_name: usize,
    /// Bit value(s) that should be given this name
    pub bits: Vec<BitVal>,
    /// Attributes for this netname
    #[serde(default)]
    pub attributes: HashMap<String, AttributeVal>,
}

pub fn read_yosys_netlist(input: &[u8]) -> Result<Netlist, serde_json::Error> {
    serde_json::from_slice(input)
}

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

    #[test]
    fn super_empty_json() {
        let result = read_yosys_netlist(br#"
            {}"#).unwrap();
        assert_eq!(result.creator, "");
        assert_eq!(result.modules.len(), 0);
    }

    #[test]
    fn empty_json() {
        let result = read_yosys_netlist(br#"
            {
              "creator": "this is a test",
              "modules": {
              }
            }"#).unwrap();
        assert_eq!(result.creator, "this is a test");
        assert_eq!(result.modules.len(), 0);
    }

    #[test]
    fn empty_json_2() {
        let result = read_yosys_netlist(br#"
            {
              "modules": {
              }
            }"#).unwrap();
        assert_eq!(result.creator, "");
        assert_eq!(result.modules.len(), 0);
    }

    #[test]
    fn bit_values_test() {
        let result = read_yosys_netlist(br#"
            {
              "modules": {
                "mymodule": {
                  "cells": {
                    "mycell": {
                      "type": "celltype",
                      "connections": {
                        "IN": [ "x", 0, "z", 234, "1", "0" ]
                      }
                    }
                  }
                }
              }
            }"#).unwrap();
        assert_eq!(result.modules.get("mymodule").unwrap().cells.get("mycell").unwrap().connections.get("IN").unwrap(),
            &vec![BitVal::S(SpecialBit::X), BitVal::N(0), BitVal::S(SpecialBit::Z), BitVal::N(234),
                BitVal::S(SpecialBit::_1), BitVal::S(SpecialBit::_0)]);
    }
}
<commit_msg>yosys-netlist-json: Add some more tests<commit_after>/*
Copyright (c) 2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use std::collections::HashMap;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

/// Legal values for the direction of a port on a module
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub enum PortDirection {
    #[serde(rename = "input")]
    Input,
    #[serde(rename = "output")]
    Output,
    #[serde(rename = "inout")]
    InOut,
}

/// Special constant bit values
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub enum SpecialBit {
    /// Constant 0
    #[serde(rename = "0")]
    _0,
    /// Constant 1
    #[serde(rename = "1")]
    _1,
    /// Constant X (invalid)
    #[serde(rename = "x")]
    X,
    /// Constant Z (tri-state)
    #[serde(rename = "z")]
    Z,
}

/// A number representing a single bit of a wire
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
pub enum BitVal {
    /// An actual signal number
    N(usize),
    /// A special constant value
    S(SpecialBit)
}

/// The value of an attribute/parameter
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
pub enum AttributeVal {
    /// Numeric attribute value
    N(usize),
    /// String attribute value
    S(String),
}

/// Represents an entire .json file used by Yosys
#[derive(Serialize, Deserialize, Debug)]
pub struct Netlist {
    /// The program that created this file.
    #[serde(default)]
    pub creator: String,
    /// A map from module names to module objects contained in this .json file
    #[serde(default)]
    pub modules: HashMap<String, Module>,
}

/// Represents one module in the Yosys hierarchy
#[derive(Serialize, Deserialize, Debug)]
pub struct Module {
    /// Module attributes
    #[serde(default)]
    pub attributes: HashMap<String, AttributeVal>,
    /// Module ports (interfaces to other modules)
    #[serde(default)]
    pub ports: HashMap<String, Port>,
    /// Module cells (objects inside this module)
    #[serde(default)]
    pub cells: HashMap<String, Cell>,
    /// Module netnames (names of wires in this module)
    #[serde(default)]
    pub netnames: HashMap<String, Netname>,
}

/// Represents a port on a module
#[derive(Serialize, Deserialize, Debug)]
pub struct Port {
    /// Port direction
    pub direction: PortDirection,
    /// Bit value(s) representing the wire(s) connected to this port
    pub bits: Vec<BitVal>,
}

/// Represents a cell in a module
#[derive(Serialize, Deserialize, Debug)]
pub struct Cell {
    /// Indicates an internal/auto-generated name that starts with `$`
    #[serde(default)]
    pub hide_name: usize,
    /// Name of the type of this cell
    #[serde(rename="type")]
    pub cell_type: String,
    /// Parameters specified on this cell
    #[serde(default)]
    pub parameters: HashMap<String, AttributeVal>,
    /// Attributes specified on this cell
    #[serde(default)]
    pub attributes: HashMap<String, AttributeVal>,
    /// The direction of the ports on this cell
    #[serde(default)]
    pub port_directions: HashMap<String, String>,
    /// Bit value(s) representing the wire(s) connected to the inputs/outputs of this cell
    pub connections: HashMap<String, Vec<BitVal>>,
}

/// Represents the name of a net in a module
#[derive(Serialize, Deserialize, Debug)]
pub struct Netname {
    /// Indicates an internal/auto-generated name that starts with `$`
    #[serde(default)]
    pub hide_name: usize,
    /// Bit value(s) that should be given this name
    pub bits: Vec<BitVal>,
    /// Attributes for this netname
    #[serde(default)]
    pub attributes: HashMap<String, AttributeVal>,
}

pub fn read_yosys_netlist(input: &[u8]) -> Result<Netlist, serde_json::Error> {
    serde_json::from_slice(input)
}

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

    #[test]
    fn super_empty_json() {
        let result = read_yosys_netlist(br#"
            {}"#).unwrap();
        assert_eq!(result.creator, "");
        assert_eq!(result.modules.len(), 0);
    }

    #[test]
    fn empty_json() {
        let result = read_yosys_netlist(br#"
            {
              "creator": "this is a test",
              "modules": {
              }
            }"#).unwrap();
        assert_eq!(result.creator, "this is a test");
        assert_eq!(result.modules.len(), 0);
    }

    #[test]
    fn empty_json_2() {
        let result = read_yosys_netlist(br#"
            {
              "modules": {
              }
            }"#).unwrap();
        assert_eq!(result.creator, "");
        assert_eq!(result.modules.len(), 0);
    }

    #[test]
    fn bit_values_test() {
        let result = read_yosys_netlist(br#"
            {
              "modules": {
                "mymodule": {
                  "cells": {
                    "mycell": {
                      "type": "celltype",
                      "connections": {
                        "IN": [ "x", 0, "z", 234, "1", "0" ]
                      }
                    }
                  }
                }
              }
            }"#).unwrap();
        assert_eq!(result.modules.get("mymodule").unwrap().cells.get("mycell").unwrap().connections.get("IN").unwrap(),
            &vec![BitVal::S(SpecialBit::X), BitVal::N(0), BitVal::S(SpecialBit::Z), BitVal::N(234),
                BitVal::S(SpecialBit::_1), BitVal::S(SpecialBit::_0)]);
    }

    #[test]
    #[should_panic]
    fn invalid_bit_value_test() {
        read_yosys_netlist(br#"
            {
              "modules": {
                "mymodule": {
                  "cells": {
                    "mycell": {
                      "type": "celltype",
                      "connections": {
                        "IN": [ "w" ]
                      }
                    }
                  }
                }
              }
            }"#).unwrap();
    }

    #[test]
    fn attribute_value_test() {
        let result = read_yosys_netlist(br#"
            {
              "modules": {
                "mymodule": {
                  "cells": {
                    "mycell": {
                      "type": "celltype",
                      "parameters": {
                        "testparam": 123
                      },
                      "connections": {}
                    }
                  }
                }
              }
            }"#).unwrap();
        assert_eq!(result.modules.get("mymodule").unwrap().cells.get("mycell").unwrap()
            .parameters.get("testparam").unwrap(), &AttributeVal::N(123));
    }

    #[test]
    #[should_panic]
    fn invalid_attribute_value_test() {
        read_yosys_netlist(br#"
            {
              "modules": {
                "mymodule": {
                  "cells": {
                    "mycell": {
                      "type": "celltype",
                      "parameters": {
                        "testparam": [123]
                      },
                      "connections": {}
                    }
                  }
                }
              }
            }"#).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate zoom;

use super::bot::*;
use super::Vec3;

static BOTS_RADIUS_MULTIPLIER: f32 = 10.0;
static RADIUS_STATIC: f32 = 5.0;
static ENERGY_RATIO: f64 = 0.002;
pub static ENERGY_THRESHOLD: i64 = 500000;

static DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {

}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        1.0
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
        }
    }

    pub fn grow(&mut self) {
        self.energy += (self.energy as f64 * ENERGY_RATIO) as i64;
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        self.energy <= 0
    }

    pub fn color(&self) -> [f32; 4] {
        [
            if self.bots.len() == 0 {
                0.0
            } else {
                self.deaths as f32 / self.bots.len() as f32
            },
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32)
    }
}
<commit_msg>change red to mean lack of food<commit_after>extern crate zoom;

use super::bot::*;
use super::Vec3;

static BOTS_RADIUS_MULTIPLIER: f32 = 10.0;
static RADIUS_STATIC: f32 = 5.0;
static ENERGY_RATIO: f64 = 0.002;
pub static ENERGY_THRESHOLD: i64 = 500000;

static DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {

}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        1.0
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
        }
    }

    pub fn grow(&mut self) {
        self.energy += (self.energy as f64 * ENERGY_RATIO) as i64;
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        self.energy <= 0
    }

    pub fn color(&self) -> [f32; 4] {
        [
            1.0 - self.energy as f32 / ENERGY_THRESHOLD as f32,
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32)
    }
}
<|endoftext|>


<commit_before>extern crate mysqlclient_sys as ffi;

use std::mem;
use std::os::raw as libc;

use super::stmt::Statement;
use crate::mysql::{MysqlType, MysqlTypeMetadata, MysqlValue};
use crate::result::QueryResult;

pub struct Binds {
    data: Vec<BindData>,
}

impl Binds {
    pub fn from_input_data<Iter>(input: Iter) -> Self
    where
        Iter: IntoIterator<Item = (MysqlTypeMetadata, Option<Vec<u8>>)>,
    {
        let data = input
            .into_iter()
            .map(|(metadata, bytes)| {
                BindData::for_input(metadata.data_type, metadata.is_unsigned as _, bytes)
            })
            .collect();

        Binds { data }
    }

    pub fn from_output_types(types: Vec<MysqlTypeMetadata>) -> Self {
        let data = types
            .into_iter()
            .map(|metadata| (metadata.data_type.into(), metadata.is_unsigned as _))
            .map(BindData::for_output)
            .collect();

        Binds { data }
    }

    pub fn from_result_metadata(fields: &[ffi::MYSQL_FIELD]) -> Self {
        let data = fields
            .iter()
            .map(|field| (field.type_, is_field_unsigned(field)))
            .map(BindData::for_output)
            .collect();

        Binds { data }
    }

    pub fn with_mysql_binds<F, T>(&mut self, f: F) -> T
    where
        F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
    {
        let mut binds = self
            .data
            .iter_mut()
            .map(|x| unsafe { x.mysql_bind() })
            .collect::<Vec<_>>();
        f(binds.as_mut_ptr())
    }

    pub fn populate_dynamic_buffers(&mut self, stmt: &Statement) -> QueryResult<()> {
        for (i, data) in self.data.iter_mut().enumerate() {
            data.did_numeric_overflow_occur()?;
            // This is safe because we are re-binding the invalidated buffers
            // at the end of this function
            unsafe {
                if let Some((mut bind, offset)) = data.bind_for_truncated_data() {
                    stmt.fetch_column(&mut bind, i, offset)?
                } else {
                    data.update_buffer_length()
                }
            }
        }

        unsafe { self.with_mysql_binds(|bind_ptr| stmt.bind_result(bind_ptr)) }
    }

    pub fn update_buffer_lengths(&mut self) {
        for data in &mut self.data {
            data.update_buffer_length();
        }
    }

    pub fn field_data(&self, idx: usize) -> Option<MysqlValue<'_>> {
        let data = &self.data[idx];
        let tpe = data.tpe.into();
        self.data[idx].bytes().map(|bytes| {
            MysqlValue::new(
                bytes,
                MysqlTypeMetadata {
                    data_type: tpe,
                    is_unsigned: data.is_unsigned != 0,
                },
            )
        })
    }
}

struct BindData {
    tpe: ffi::enum_field_types,
    bytes: Vec<u8>,
    length: libc::c_ulong,
    is_null: ffi::my_bool,
    is_truncated: Option<ffi::my_bool>,
    is_unsigned: ffi::my_bool,
}

impl BindData {
    fn for_input(tpe: MysqlType, is_unsigned: ffi::my_bool, data: Option<Vec<u8>>) -> Self {
        let is_null = if data.is_none() { 1 } else { 0 };
        let bytes = data.unwrap_or_default();
        let length = bytes.len() as libc::c_ulong;

        BindData {
            tpe: tpe.into(),
            bytes,
            length,
            is_null,
            is_truncated: None,
            is_unsigned,
        }
    }

    fn for_output((tpe, is_unsigned): (ffi::enum_field_types, ffi::my_bool)) -> Self {
        let bytes = known_buffer_size_for_ffi_type(tpe)
            .map(|len| vec![0; len])
            .unwrap_or_default();
        let length = bytes.len() as libc::c_ulong;

        BindData {
            tpe,
            bytes,
            length,
            is_null: 0,
            is_truncated: Some(0),
            is_unsigned,
        }
    }

    fn is_truncated(&self) -> bool {
        self.is_truncated.unwrap_or(0) != 0
    }

    fn is_fixed_size_buffer(&self) -> bool {
        known_buffer_size_for_ffi_type(self.tpe).is_some()
    }

    fn bytes(&self) -> Option<&[u8]> {
        if self.is_null == 0 {
            Some(&*self.bytes)
        } else {
            None
        }
    }

    fn update_buffer_length(&mut self) {
        use std::cmp::min;

        let actual_bytes_in_buffer = min(self.bytes.capacity(), self.length as usize);
        unsafe { self.bytes.set_len(actual_bytes_in_buffer) }
    }

    unsafe fn mysql_bind(&mut self) -> ffi::MYSQL_BIND {
        let mut bind: ffi::MYSQL_BIND = mem::zeroed();
        bind.buffer_type = self.tpe;
        bind.buffer = self.bytes.as_mut_ptr() as *mut libc::c_void;
        bind.buffer_length = self.bytes.capacity() as libc::c_ulong;
        bind.length = &mut self.length;
        bind.is_null = &mut self.is_null;
        bind.is_unsigned = self.is_unsigned;

        if let Some(ref mut is_truncated) = self.is_truncated {
            bind.error = is_truncated;
        }

        bind
    }

    /// Resizes the byte buffer to fit the value of `self.length`, and returns
    /// a tuple of a bind pointing at the truncated data, and the offset to use
    /// in order to read the truncated data into it.
    ///
    /// This invalidates the bind previously returned by `mysql_bind`. Calling
    /// this function is unsafe unless the binds are immediately rebound.
    unsafe fn bind_for_truncated_data(&mut self) -> Option<(ffi::MYSQL_BIND, usize)> {
        if self.is_truncated() {
            let offset = self.bytes.capacity();
            let truncated_amount = self.length as usize - offset;

            debug_assert!(
                truncated_amount > 0,
                "output buffers were invalidated \
                 without calling `mysql_stmt_bind_result`"
            );
            self.bytes.set_len(offset);
            self.bytes.reserve(truncated_amount);
            self.bytes.set_len(self.length as usize);

            let mut bind = self.mysql_bind();
            bind.buffer = self.bytes[offset..].as_mut_ptr() as *mut libc::c_void;
            bind.buffer_length = truncated_amount as libc::c_ulong;
            Some((bind, offset))
        } else {
            None
        }
    }

    fn did_numeric_overflow_occur(&self) -> QueryResult<()> {
        use crate::result::Error::DeserializationError;

        if self.is_truncated() && self.is_fixed_size_buffer() {
            Err(DeserializationError(
                "Numeric overflow/underflow occurred".into(),
            ))
        } else {
            Ok(())
        }
    }
}

impl From<MysqlType> for ffi::enum_field_types {
    fn from(tpe: MysqlType) -> Self {
        use self::ffi::enum_field_types::*;

        match tpe {
            MysqlType::Tiny => MYSQL_TYPE_TINY,
            MysqlType::Short => MYSQL_TYPE_SHORT,
            MysqlType::Long => MYSQL_TYPE_LONG,
            MysqlType::LongLong => MYSQL_TYPE_LONGLONG,
            MysqlType::Float => MYSQL_TYPE_FLOAT,
            MysqlType::Double => MYSQL_TYPE_DOUBLE,
            MysqlType::Time => MYSQL_TYPE_TIME,
            MysqlType::Date => MYSQL_TYPE_DATE,
            MysqlType::DateTime => MYSQL_TYPE_DATETIME,
            MysqlType::Timestamp => MYSQL_TYPE_TIMESTAMP,
            MysqlType::String => MYSQL_TYPE_STRING,
            MysqlType::Blob => MYSQL_TYPE_BLOB,
            MysqlType::Numeric => MYSQL_TYPE_NEWDECIMAL,
        }
    }
}

impl From<ffi::enum_field_types> for MysqlType {
    fn from(tpe: ffi::enum_field_types) -> Self {
        use self::ffi::enum_field_types::*;

        match tpe {
            MYSQL_TYPE_TINY => MysqlType::Tiny,
            MYSQL_TYPE_SHORT => MysqlType::Short,
            MYSQL_TYPE_INT24 | MYSQL_TYPE_LONG => MysqlType::Long,
            MYSQL_TYPE_LONGLONG => MysqlType::LongLong,
            MYSQL_TYPE_FLOAT => MysqlType::Float,
            MYSQL_TYPE_DOUBLE => MysqlType::Double,
            MYSQL_TYPE_TIME => MysqlType::Time,
            MYSQL_TYPE_DATE => MysqlType::Date,
            MYSQL_TYPE_DATETIME => MysqlType::DateTime,
            MYSQL_TYPE_TIMESTAMP => MysqlType::Timestamp,
            MYSQL_TYPE_STRING => MysqlType::String,
            MYSQL_TYPE_BLOB => MysqlType::Blob,
            MYSQL_TYPE_DECIMAL | MYSQL_TYPE_NEWDECIMAL => MysqlType::Numeric,
            MYSQL_TYPE_NULL
            | MYSQL_TYPE_YEAR
            | MYSQL_TYPE_NEWDATE
            | MYSQL_TYPE_VARCHAR
            | MYSQL_TYPE_BIT
            | MYSQL_TYPE_TIMESTAMP2
            | MYSQL_TYPE_DATETIME2
            | MYSQL_TYPE_TIME2
            | MYSQL_TYPE_JSON
            | MYSQL_TYPE_ENUM
            | MYSQL_TYPE_SET
            | MYSQL_TYPE_TINY_BLOB
            | MYSQL_TYPE_MEDIUM_BLOB
            | MYSQL_TYPE_LONG_BLOB
            | MYSQL_TYPE_VAR_STRING
            | MYSQL_TYPE_GEOMETRY => unimplemented!(),
        }
    }
}

fn known_buffer_size_for_ffi_type(tpe: ffi::enum_field_types) -> Option<usize> {
    use self::ffi::enum_field_types as t;
    use std::mem::size_of;

    match tpe {
        t::MYSQL_TYPE_TINY => Some(1),
        t::MYSQL_TYPE_YEAR | t::MYSQL_TYPE_SHORT => Some(2),
        t::MYSQL_TYPE_INT24 | t::MYSQL_TYPE_LONG | t::MYSQL_TYPE_FLOAT => Some(4),
        t::MYSQL_TYPE_LONGLONG | t::MYSQL_TYPE_DOUBLE => Some(8),
        t::MYSQL_TYPE_TIME
        | t::MYSQL_TYPE_DATE
        | t::MYSQL_TYPE_DATETIME
        | t::MYSQL_TYPE_TIMESTAMP => Some(size_of::<ffi::MYSQL_TIME>()),
        _ => None,
    }
}

fn is_field_unsigned(field: &ffi::MYSQL_FIELD) -> ffi::my_bool {
    const UNSIGNED_FLAG: libc::c_uint = 32;
    (field.flags & UNSIGNED_FLAG > 0) as _
}
<commit_msg>Improve type mapping in mysql backend<commit_after>extern crate mysqlclient_sys as ffi;

use std::mem;
use std::os::raw as libc;

use super::stmt::Statement;
use crate::mysql::{MysqlType, MysqlTypeMetadata, MysqlValue};
use crate::result::QueryResult;

pub struct Binds {
    data: Vec<BindData>,
}

impl Binds {
    pub fn from_input_data<Iter>(input: Iter) -> Self
    where
        Iter: IntoIterator<Item = (MysqlTypeMetadata, Option<Vec<u8>>)>,
    {
        let data = input
            .into_iter()
            .map(|(metadata, bytes)| {
                BindData::for_input(metadata.data_type, metadata.is_unsigned as _, bytes)
            })
            .collect();

        Binds { data }
    }

    pub fn from_output_types(types: Vec<MysqlTypeMetadata>) -> Self {
        let data = types
            .into_iter()
            .map(|metadata| (metadata.data_type.into(), metadata.is_unsigned as _))
            .map(BindData::for_output)
            .collect();

        Binds { data }
    }

    pub fn from_result_metadata(fields: &[ffi::MYSQL_FIELD]) -> Self {
        let data = fields
            .iter()
            .map(|field| (field.type_, is_field_unsigned(field)))
            .map(BindData::for_output)
            .collect();

        Binds { data }
    }

    pub fn with_mysql_binds<F, T>(&mut self, f: F) -> T
    where
        F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
    {
        let mut binds = self
            .data
            .iter_mut()
            .map(|x| unsafe { x.mysql_bind() })
            .collect::<Vec<_>>();
        f(binds.as_mut_ptr())
    }

    pub fn populate_dynamic_buffers(&mut self, stmt: &Statement) -> QueryResult<()> {
        for (i, data) in self.data.iter_mut().enumerate() {
            data.did_numeric_overflow_occur()?;
            // This is safe because we are re-binding the invalidated buffers
            // at the end of this function
            unsafe {
                if let Some((mut bind, offset)) = data.bind_for_truncated_data() {
                    stmt.fetch_column(&mut bind, i, offset)?
                } else {
                    data.update_buffer_length()
                }
            }
        }

        unsafe { self.with_mysql_binds(|bind_ptr| stmt.bind_result(bind_ptr)) }
    }

    pub fn update_buffer_lengths(&mut self) {
        for data in &mut self.data {
            data.update_buffer_length();
        }
    }

    pub fn field_data(&self, idx: usize) -> Option<MysqlValue<'_>> {
        let data = &self.data[idx];
        let tpe = data.tpe.into();
        self.data[idx].bytes().map(|bytes| {
            MysqlValue::new(
                bytes,
                MysqlTypeMetadata {
                    data_type: tpe,
                    is_unsigned: data.is_unsigned != 0,
                },
            )
        })
    }
}

struct BindData {
    tpe: ffi::enum_field_types,
    bytes: Vec<u8>,
    length: libc::c_ulong,
    is_null: ffi::my_bool,
    is_truncated: Option<ffi::my_bool>,
    is_unsigned: ffi::my_bool,
}

impl BindData {
    fn for_input(tpe: MysqlType, is_unsigned: ffi::my_bool, data: Option<Vec<u8>>) -> Self {
        let is_null = if data.is_none() { 1 } else { 0 };
        let bytes = data.unwrap_or_default();
        let length = bytes.len() as libc::c_ulong;

        BindData {
            tpe: tpe.into(),
            bytes,
            length,
            is_null,
            is_truncated: None,
            is_unsigned,
        }
    }

    fn for_output((tpe, is_unsigned): (ffi::enum_field_types, ffi::my_bool)) -> Self {
        let bytes = known_buffer_size_for_ffi_type(tpe)
            .map(|len| vec![0; len])
            .unwrap_or_default();
        let length = bytes.len() as libc::c_ulong;

        BindData {
            tpe,
            bytes,
            length,
            is_null: 0,
            is_truncated: Some(0),
            is_unsigned,
        }
    }

    fn is_truncated(&self) -> bool {
        self.is_truncated.unwrap_or(0) != 0
    }

    fn is_fixed_size_buffer(&self) -> bool {
        known_buffer_size_for_ffi_type(self.tpe).is_some()
    }

    fn bytes(&self) -> Option<&[u8]> {
        if self.is_null == 0 {
            Some(&*self.bytes)
        } else {
            None
        }
    }

    fn update_buffer_length(&mut self) {
        use std::cmp::min;

        let actual_bytes_in_buffer = min(self.bytes.capacity(), self.length as usize);
        unsafe { self.bytes.set_len(actual_bytes_in_buffer) }
    }

    unsafe fn mysql_bind(&mut self) -> ffi::MYSQL_BIND {
        let mut bind: ffi::MYSQL_BIND = mem::zeroed();
        bind.buffer_type = self.tpe;
        bind.buffer = self.bytes.as_mut_ptr() as *mut libc::c_void;
        bind.buffer_length = self.bytes.capacity() as libc::c_ulong;
        bind.length = &mut self.length;
        bind.is_null = &mut self.is_null;
        bind.is_unsigned = self.is_unsigned;

        if let Some(ref mut is_truncated) = self.is_truncated {
            bind.error = is_truncated;
        }

        bind
    }

    /// Resizes the byte buffer to fit the value of `self.length`, and returns
    /// a tuple of a bind pointing at the truncated data, and the offset to use
    /// in order to read the truncated data into it.
    ///
    /// This invalidates the bind previously returned by `mysql_bind`. Calling
    /// this function is unsafe unless the binds are immediately rebound.
    unsafe fn bind_for_truncated_data(&mut self) -> Option<(ffi::MYSQL_BIND, usize)> {
        if self.is_truncated() {
            let offset = self.bytes.capacity();
            let truncated_amount = self.length as usize - offset;

            debug_assert!(
                truncated_amount > 0,
                "output buffers were invalidated \
                 without calling `mysql_stmt_bind_result`"
            );
            self.bytes.set_len(offset);
            self.bytes.reserve(truncated_amount);
            self.bytes.set_len(self.length as usize);

            let mut bind = self.mysql_bind();
            bind.buffer = self.bytes[offset..].as_mut_ptr() as *mut libc::c_void;
            bind.buffer_length = truncated_amount as libc::c_ulong;
            Some((bind, offset))
        } else {
            None
        }
    }

    fn did_numeric_overflow_occur(&self) -> QueryResult<()> {
        use crate::result::Error::DeserializationError;

        if self.is_truncated() && self.is_fixed_size_buffer() {
            Err(DeserializationError(
                "Numeric overflow/underflow occurred".into(),
            ))
        } else {
            Ok(())
        }
    }
}

impl From<MysqlType> for ffi::enum_field_types {
    fn from(tpe: MysqlType) -> Self {
        use self::ffi::enum_field_types::*;

        match tpe {
            MysqlType::Tiny => MYSQL_TYPE_TINY,
            MysqlType::Short => MYSQL_TYPE_SHORT,
            MysqlType::Long => MYSQL_TYPE_LONG,
            MysqlType::LongLong => MYSQL_TYPE_LONGLONG,
            MysqlType::Float => MYSQL_TYPE_FLOAT,
            MysqlType::Double => MYSQL_TYPE_DOUBLE,
            MysqlType::Time => MYSQL_TYPE_TIME,
            MysqlType::Date => MYSQL_TYPE_DATE,
            MysqlType::DateTime => MYSQL_TYPE_DATETIME,
            MysqlType::Timestamp => MYSQL_TYPE_TIMESTAMP,
            MysqlType::String => MYSQL_TYPE_STRING,
            MysqlType::Blob => MYSQL_TYPE_BLOB,
            MysqlType::Numeric => MYSQL_TYPE_NEWDECIMAL,
        }
    }
}

impl From<ffi::enum_field_types> for MysqlType {
    fn from(tpe: ffi::enum_field_types) -> Self {
        use self::ffi::enum_field_types::*;

        // https://docs.oracle.com/cd/E17952_01/mysql-8.0-en/c-api-data-structures.html
        // https://dev.mysql.com/doc/dev/mysql-server/8.0.12/binary__log__types_8h.html
        // https://dev.mysql.com/doc/internals/en/binary-protocol-value.html
        // https://mariadb.com/kb/en/packet_bindata/
        match tpe {
            MYSQL_TYPE_TINY => MysqlType::Tiny,
            MYSQL_TYPE_YEAR | MYSQL_TYPE_SHORT => MysqlType::Short,
            MYSQL_TYPE_INT24 | MYSQL_TYPE_LONG => MysqlType::Long,
            MYSQL_TYPE_LONGLONG => MysqlType::LongLong,
            MYSQL_TYPE_FLOAT => MysqlType::Float,
            MYSQL_TYPE_DOUBLE => MysqlType::Double,
            MYSQL_TYPE_TIME => MysqlType::Time,
            MYSQL_TYPE_DATE => MysqlType::Date,
            MYSQL_TYPE_DATETIME => MysqlType::DateTime,
            MYSQL_TYPE_TIMESTAMP => MysqlType::Timestamp,
            MYSQL_TYPE_VAR_STRING | MYSQL_TYPE_VARCHAR | MYSQL_TYPE_STRING => MysqlType::String,
            MYSQL_TYPE_BLOB
            | MYSQL_TYPE_TINY_BLOB
            | MYSQL_TYPE_MEDIUM_BLOB
            | MYSQL_TYPE_LONG_BLOB => MysqlType::Blob,
            MYSQL_TYPE_DECIMAL | MYSQL_TYPE_NEWDECIMAL => MysqlType::Numeric,
            // Null value
            MYSQL_TYPE_NULL |
            // bit type
            // same encoding as string
            MYSQL_TYPE_BIT |
            // enum type
            // same encoding as string
            MYSQL_TYPE_ENUM |
            // set type
            // same encoding as string
            MYSQL_TYPE_SET |
            // spatial type
            // same encoding as string
            MYSQL_TYPE_GEOMETRY |
            // json type, only available on newer mysql versions
            // same encoding as string
            MYSQL_TYPE_JSON => unimplemented!(
                "Hit currently unsupported type, those variants should \
                 probably be variants of MysqlType or at least be mapped \
                 to one of the existing types"
            ),
            MYSQL_TYPE_NEWDATE
            | MYSQL_TYPE_TIME2
            | MYSQL_TYPE_DATETIME2
            | MYSQL_TYPE_TIMESTAMP2 => panic!(
                "The mysql documentation states that this types are \
                 only used on server side, so if you see this error \
                 something has gone wrong. Please open a issue at \
                 the diesel github repo."
            ),
        }
    }
}

fn known_buffer_size_for_ffi_type(tpe: ffi::enum_field_types) -> Option<usize> {
    use self::ffi::enum_field_types as t;
    use std::mem::size_of;

    match tpe {
        t::MYSQL_TYPE_TINY => Some(1),
        t::MYSQL_TYPE_YEAR | t::MYSQL_TYPE_SHORT => Some(2),
        t::MYSQL_TYPE_INT24 | t::MYSQL_TYPE_LONG | t::MYSQL_TYPE_FLOAT => Some(4),
        t::MYSQL_TYPE_LONGLONG | t::MYSQL_TYPE_DOUBLE => Some(8),
        t::MYSQL_TYPE_TIME
        | t::MYSQL_TYPE_DATE
        | t::MYSQL_TYPE_DATETIME
        | t::MYSQL_TYPE_TIMESTAMP => Some(size_of::<ffi::MYSQL_TIME>()),
        _ => None,
    }
}

fn is_field_unsigned(field: &ffi::MYSQL_FIELD) -> ffi::my_bool {
    const UNSIGNED_FLAG: libc::c_uint = 32;
    (field.flags & UNSIGNED_FLAG > 0) as _
}
<|endoftext|>


<commit_before>extern crate libsqlite3_sys as ffi;
extern crate libc;

#[doc(hidden)]
pub mod raw;
mod stmt;
mod statement_iterator;
mod sqlite_value;

pub use self::sqlite_value::SqliteValue;

use std::any::TypeId;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::ffi::CStr;

use connection::{SimpleConnection, Connection};
use query_builder::*;
use query_builder::bind_collector::RawBytesBindCollector;
use query_source::*;
use result::*;
use result::Error::QueryBuilderError;
use self::raw::RawConnection;
use self::statement_iterator::StatementIterator;
use self::stmt::{Statement, StatementUse};
use sqlite::Sqlite;
use super::query_builder::SqliteQueryBuilder;
use types::HasSqlType;

#[allow(missing_debug_implementations)]
pub struct SqliteConnection {
    statement_cache: RefCell<HashMap<QueryCacheKey, StatementUse>>,
    raw_connection: RawConnection,
    transaction_depth: Cell<i32>,
}

#[derive(Hash, PartialEq, Eq)]
enum QueryCacheKey {
    Sql(String),
    Type(TypeId),
}

// This relies on the invariant that RawConnection or Statement are never
// leaked. If a reference to one of those was held on a different thread, this
// would not be thread safe.
unsafe impl Send for SqliteConnection {}

impl SimpleConnection for SqliteConnection {
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        self.raw_connection.exec(query)
    }
}

impl Connection for SqliteConnection {
    type Backend = Sqlite;

    fn establish(database_url: &str) -> ConnectionResult<Self> {
        RawConnection::establish(database_url).map(|conn| {
            SqliteConnection {
                statement_cache: RefCell::new(HashMap::new()),
                raw_connection: conn,
                transaction_depth: Cell::new(0),
            }
        })
    }

    fn execute(&self, query: &str) -> QueryResult<usize> {
        try!(self.batch_execute(query));
        Ok(self.raw_connection.rows_affected_by_last_query())
    }

    fn query_all<T, U>(&self, source: T) -> QueryResult<Vec<U>> where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        Self::Backend: HasSqlType<T::SqlType>,
        U: Queryable<T::SqlType, Self::Backend>,
    {
        let statement = try!(self.prepare_query(&source.as_query()));
        let mut statement_ref = statement.borrow_mut();
        StatementIterator::new(&mut statement_ref).collect()
    }

    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize> where
        T: QueryFragment<Self::Backend> + QueryId,
    {
        let stmt = try!(self.prepare_query(source));
        try!(stmt.borrow().run());
        Ok(self.raw_connection.rows_affected_by_last_query())
    }

    fn silence_notices<F: FnOnce() -> T, T>(&self, f: F) -> T {
        f()
    }

    fn begin_transaction(&self) -> QueryResult<()> {
        let transaction_depth = self.transaction_depth.get();
        self.change_transaction_depth(1, if transaction_depth == 0 {
            self.execute("BEGIN")
        } else {
            self.execute(&format!("SAVEPOINT diesel_savepoint_{}", transaction_depth))
        })
    }

    fn rollback_transaction(&self) -> QueryResult<()> {
        let transaction_depth = self.transaction_depth.get();
        self.change_transaction_depth(-1, if transaction_depth == 1 {
            self.execute("ROLLBACK")
        } else {
            self.execute(&format!("ROLLBACK TO SAVEPOINT diesel_savepoint_{}",
                                  transaction_depth - 1))
        })
    }

    fn commit_transaction(&self) -> QueryResult<()> {
        let transaction_depth = self.transaction_depth.get();
        self.change_transaction_depth(-1, if transaction_depth <= 1 {
            self.execute("COMMIT")
        } else {
            self.execute(&format!("RELEASE SAVEPOINT diesel_savepoint_{}",
                                  transaction_depth - 1))
        })
    }

    fn get_transaction_depth(&self) -> i32 {
        self.transaction_depth.get()
    }

    fn setup_helper_functions(&self) {
        // this will be implemented at least when timestamps are supported in SQLite
    }
}

impl SqliteConnection {
    fn prepare_query<T: QueryFragment<Sqlite> + QueryId>(&self, source: &T) -> QueryResult<StatementUse> {
        let result = try!(self.cached_prepared_statement(source));

        let mut bind_collector = RawBytesBindCollector::<Sqlite>::new();
        try!(source.collect_binds(&mut bind_collector));
        {
            let mut stmt = result.borrow_mut();
            for (tpe, value) in bind_collector.binds.into_iter() {
                try!(stmt.bind(tpe, value));
            }
        }

        Ok(result)
    }

    fn change_transaction_depth(&self, by: i32, query: QueryResult<usize>) -> QueryResult<()> {
        if query.is_ok() {
            self.transaction_depth.set(self.transaction_depth.get() + by);
        }
        query.map(|_| ())
    }

    fn cached_prepared_statement<T: QueryFragment<Sqlite> + QueryId>(&self, source: &T)
        -> QueryResult<StatementUse>
    {
        let cache_key = try!(cache_key(source));

        let mut cache = self.statement_cache.borrow_mut();
        // FIXME: This can be cleaned up once https://github.com/rust-lang/rust/issues/32281
        // is stable
        if cache.contains_key(&cache_key) {
            Ok(cache[&cache_key].clone())
        } else {
            let statement = {
                let sql = try!(sql_from_cache_key(&cache_key, source));

                Statement::prepare(&self.raw_connection, &sql)
                    .map(StatementUse::new)
            };
            if !source.is_safe_to_cache_prepared() {
                return statement;
            }
            let entry = cache.entry(cache_key);
            Ok(entry.or_insert(try!(statement)).clone())
        }
    }
}

fn cache_key<T: QueryFragment<Sqlite> + QueryId>(source: &T)
    -> QueryResult<QueryCacheKey>
{
    match T::query_id() {
        Some(id) => Ok(QueryCacheKey::Type(id)),
        None => to_sql(source).map(QueryCacheKey::Sql),
    }
}

fn sql_from_cache_key<'a, T: QueryFragment<Sqlite>>(key: &'a QueryCacheKey, source: &T)
    -> QueryResult<Cow<'a, str>>
{
    match key {
        &QueryCacheKey::Sql(ref sql) => Ok(Cow::Borrowed(sql)),
        _ => to_sql(source).map(Cow::Owned),
    }
}

fn to_sql<T: QueryFragment<Sqlite>>(source: &T) -> QueryResult<String> {
    let mut query_builder = SqliteQueryBuilder::new();
    try!(source.to_sql(&mut query_builder).map_err(QueryBuilderError));
    Ok(query_builder.sql)
}

fn error_message(err_code: libc::c_int) -> &'static str {
    unsafe {
        let message_ptr = ffi::sqlite3_errstr(err_code);
        let result = CStr::from_ptr(message_ptr);
        result.to_str().unwrap()
    }
}

#[cfg(test)]
mod tests {
    use expression::AsExpression;
    use expression::dsl::sql;
    use prelude::*;
    use super::*;
    use types::Integer;

    #[test]
    fn prepared_statements_are_cached_when_run() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let query = ::select(AsExpression::<Integer>::as_expression(1));

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(1, connection.statement_cache.borrow().len());
    }

    #[test]
    fn sql_literal_nodes_are_not_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let query = ::select(sql::<Integer>("1"));

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.borrow().len());
    }

    #[test]
    fn queries_containing_sql_literal_nodes_are_not_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let one_as_expr = AsExpression::<Integer>::as_expression(1);
        let query = ::select(one_as_expr.eq(sql::<Integer>("1")));

        assert_eq!(Ok(true), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.borrow().len());
    }

    #[test]
    fn queries_containing_in_with_vec_are_not_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let one_as_expr = AsExpression::<Integer>::as_expression(1);
        let query = ::select(one_as_expr.eq_any(vec![1, 2, 3]));

        assert_eq!(Ok(true), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.borrow().len());
    }

    #[test]
    fn queries_containing_in_with_subselect_are_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let one_as_expr = AsExpression::<Integer>::as_expression(1);
        let query = ::select(one_as_expr.eq_any(::select(one_as_expr)));

        assert_eq!(Ok(true), query.get_result(&connection));
        assert_eq!(1, connection.statement_cache.borrow().len());
    }
}
<commit_msg>remove usage of sqlite3_errstr<commit_after>extern crate libsqlite3_sys as ffi;
extern crate libc;

#[doc(hidden)]
pub mod raw;
mod stmt;
mod statement_iterator;
mod sqlite_value;

pub use self::sqlite_value::SqliteValue;

use std::any::TypeId;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;

use connection::{SimpleConnection, Connection};
use query_builder::*;
use query_builder::bind_collector::RawBytesBindCollector;
use query_source::*;
use result::*;
use result::Error::QueryBuilderError;
use self::raw::RawConnection;
use self::statement_iterator::StatementIterator;
use self::stmt::{Statement, StatementUse};
use sqlite::Sqlite;
use super::query_builder::SqliteQueryBuilder;
use types::HasSqlType;

#[allow(missing_debug_implementations)]
pub struct SqliteConnection {
    statement_cache: RefCell<HashMap<QueryCacheKey, StatementUse>>,
    raw_connection: RawConnection,
    transaction_depth: Cell<i32>,
}

#[derive(Hash, PartialEq, Eq)]
enum QueryCacheKey {
    Sql(String),
    Type(TypeId),
}

// This relies on the invariant that RawConnection or Statement are never
// leaked. If a reference to one of those was held on a different thread, this
// would not be thread safe.
unsafe impl Send for SqliteConnection {}

impl SimpleConnection for SqliteConnection {
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        self.raw_connection.exec(query)
    }
}

impl Connection for SqliteConnection {
    type Backend = Sqlite;

    fn establish(database_url: &str) -> ConnectionResult<Self> {
        RawConnection::establish(database_url).map(|conn| {
            SqliteConnection {
                statement_cache: RefCell::new(HashMap::new()),
                raw_connection: conn,
                transaction_depth: Cell::new(0),
            }
        })
    }

    fn execute(&self, query: &str) -> QueryResult<usize> {
        try!(self.batch_execute(query));
        Ok(self.raw_connection.rows_affected_by_last_query())
    }

    fn query_all<T, U>(&self, source: T) -> QueryResult<Vec<U>> where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        Self::Backend: HasSqlType<T::SqlType>,
        U: Queryable<T::SqlType, Self::Backend>,
    {
        let statement = try!(self.prepare_query(&source.as_query()));
        let mut statement_ref = statement.borrow_mut();
        StatementIterator::new(&mut statement_ref).collect()
    }

    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize> where
        T: QueryFragment<Self::Backend> + QueryId,
    {
        let stmt = try!(self.prepare_query(source));
        try!(stmt.borrow().run());
        Ok(self.raw_connection.rows_affected_by_last_query())
    }

    fn silence_notices<F: FnOnce() -> T, T>(&self, f: F) -> T {
        f()
    }

    fn begin_transaction(&self) -> QueryResult<()> {
        let transaction_depth = self.transaction_depth.get();
        self.change_transaction_depth(1, if transaction_depth == 0 {
            self.execute("BEGIN")
        } else {
            self.execute(&format!("SAVEPOINT diesel_savepoint_{}", transaction_depth))
        })
    }

    fn rollback_transaction(&self) -> QueryResult<()> {
        let transaction_depth = self.transaction_depth.get();
        self.change_transaction_depth(-1, if transaction_depth == 1 {
            self.execute("ROLLBACK")
        } else {
            self.execute(&format!("ROLLBACK TO SAVEPOINT diesel_savepoint_{}",
                                  transaction_depth - 1))
        })
    }

    fn commit_transaction(&self) -> QueryResult<()> {
        let transaction_depth = self.transaction_depth.get();
        self.change_transaction_depth(-1, if transaction_depth <= 1 {
            self.execute("COMMIT")
        } else {
            self.execute(&format!("RELEASE SAVEPOINT diesel_savepoint_{}",
                                  transaction_depth - 1))
        })
    }

    fn get_transaction_depth(&self) -> i32 {
        self.transaction_depth.get()
    }

    fn setup_helper_functions(&self) {
        // this will be implemented at least when timestamps are supported in SQLite
    }
}

impl SqliteConnection {
    fn prepare_query<T: QueryFragment<Sqlite> + QueryId>(&self, source: &T) -> QueryResult<StatementUse> {
        let result = try!(self.cached_prepared_statement(source));

        let mut bind_collector = RawBytesBindCollector::<Sqlite>::new();
        try!(source.collect_binds(&mut bind_collector));
        {
            let mut stmt = result.borrow_mut();
            for (tpe, value) in bind_collector.binds.into_iter() {
                try!(stmt.bind(tpe, value));
            }
        }

        Ok(result)
    }

    fn change_transaction_depth(&self, by: i32, query: QueryResult<usize>) -> QueryResult<()> {
        if query.is_ok() {
            self.transaction_depth.set(self.transaction_depth.get() + by);
        }
        query.map(|_| ())
    }

    fn cached_prepared_statement<T: QueryFragment<Sqlite> + QueryId>(&self, source: &T)
        -> QueryResult<StatementUse>
    {
        let cache_key = try!(cache_key(source));

        let mut cache = self.statement_cache.borrow_mut();
        // FIXME: This can be cleaned up once https://github.com/rust-lang/rust/issues/32281
        // is stable
        if cache.contains_key(&cache_key) {
            Ok(cache[&cache_key].clone())
        } else {
            let statement = {
                let sql = try!(sql_from_cache_key(&cache_key, source));

                Statement::prepare(&self.raw_connection, &sql)
                    .map(StatementUse::new)
            };
            if !source.is_safe_to_cache_prepared() {
                return statement;
            }
            let entry = cache.entry(cache_key);
            Ok(entry.or_insert(try!(statement)).clone())
        }
    }
}

fn cache_key<T: QueryFragment<Sqlite> + QueryId>(source: &T)
    -> QueryResult<QueryCacheKey>
{
    match T::query_id() {
        Some(id) => Ok(QueryCacheKey::Type(id)),
        None => to_sql(source).map(QueryCacheKey::Sql),
    }
}

fn sql_from_cache_key<'a, T: QueryFragment<Sqlite>>(key: &'a QueryCacheKey, source: &T)
    -> QueryResult<Cow<'a, str>>
{
    match key {
        &QueryCacheKey::Sql(ref sql) => Ok(Cow::Borrowed(sql)),
        _ => to_sql(source).map(Cow::Owned),
    }
}

fn to_sql<T: QueryFragment<Sqlite>>(source: &T) -> QueryResult<String> {
    let mut query_builder = SqliteQueryBuilder::new();
    try!(source.to_sql(&mut query_builder).map_err(QueryBuilderError));
    Ok(query_builder.sql)
}

fn error_message(err_code: libc::c_int) -> &'static str {
    ffi::code_to_str(err_code)
}

#[cfg(test)]
mod tests {
    use expression::AsExpression;
    use expression::dsl::sql;
    use prelude::*;
    use super::*;
    use types::Integer;

    #[test]
    fn prepared_statements_are_cached_when_run() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let query = ::select(AsExpression::<Integer>::as_expression(1));

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(1, connection.statement_cache.borrow().len());
    }

    #[test]
    fn sql_literal_nodes_are_not_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let query = ::select(sql::<Integer>("1"));

        assert_eq!(Ok(1), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.borrow().len());
    }

    #[test]
    fn queries_containing_sql_literal_nodes_are_not_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let one_as_expr = AsExpression::<Integer>::as_expression(1);
        let query = ::select(one_as_expr.eq(sql::<Integer>("1")));

        assert_eq!(Ok(true), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.borrow().len());
    }

    #[test]
    fn queries_containing_in_with_vec_are_not_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let one_as_expr = AsExpression::<Integer>::as_expression(1);
        let query = ::select(one_as_expr.eq_any(vec![1, 2, 3]));

        assert_eq!(Ok(true), query.get_result(&connection));
        assert_eq!(0, connection.statement_cache.borrow().len());
    }

    #[test]
    fn queries_containing_in_with_subselect_are_cached() {
        let connection = SqliteConnection::establish(":memory:").unwrap();
        let one_as_expr = AsExpression::<Integer>::as_expression(1);
        let query = ::select(one_as_expr.eq_any(::select(one_as_expr)));

        assert_eq!(Ok(true), query.get_result(&connection));
        assert_eq!(1, connection.statement_cache.borrow().len());
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use sdl2::{self, INIT_VIDEO};
use sdl2::video::{Window, WindowPos, OPENGL};
use sdl2::render::{Renderer, RenderDriverIndex, ACCELERATED};
use sdl2_image::{self, LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::event::Event;
use sdl2::keycode::KeyCode;

pub fn main(png: &Path) {

    let context = sdl2::init(INIT_VIDEO).unwrap();
    sdl2_image::init(INIT_PNG | INIT_JPG);

    let window = Window::new(
          "rust-sdl2 demo: Video",
          WindowPos::PosCentered,
          WindowPos::PosCentered,
          800,
          600,
          OPENGL).unwrap();

    let renderer = Renderer::from_window(
          window,
          RenderDriverIndex::Auto,
          ACCELERATED).unwrap();

    let mut texture = renderer.load_texture(png).unwrap();

    // Draws and shows the loaded texture.
    let mut drawer = renderer.drawer();
    drawer.copy(&mut texture, None, None);
    drawer.present();

    let mut event_pump = context.event_pump();
    'mainloop: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit{..} |
                Event::KeyDown {keycode: KeyCode::Escape, ..} =>
                    break 'mainloop,
                _ => {}
            }
        }
    }

    sdl2_image::quit();
}
<commit_msg>update Window::new to take &context<commit_after>use std::path::Path;
use sdl2::{self, INIT_VIDEO};
use sdl2::video::{Window, WindowPos, OPENGL};
use sdl2::render::{Renderer, RenderDriverIndex, ACCELERATED};
use sdl2_image::{self, LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::event::Event;
use sdl2::keycode::KeyCode;

pub fn main(png: &Path) {

    let context = sdl2::init(INIT_VIDEO).unwrap();
    sdl2_image::init(INIT_PNG | INIT_JPG);

    let window = Window::new(
          &context,
          "rust-sdl2 demo: Video",
          WindowPos::PosCentered,
          WindowPos::PosCentered,
          800,
          600,
          OPENGL).unwrap();

    let renderer = Renderer::from_window(
          window,
          RenderDriverIndex::Auto,
          ACCELERATED).unwrap();

    let mut texture = renderer.load_texture(png).unwrap();

    // Draws and shows the loaded texture.
    let mut drawer = renderer.drawer();
    drawer.copy(&mut texture, None, None);
    drawer.present();

    let mut event_pump = context.event_pump();
    'mainloop: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit{..} |
                Event::KeyDown {keycode: KeyCode::Escape, ..} =>
                    break 'mainloop,
                _ => {}
            }
        }
    }

    sdl2_image::quit();
}
<|endoftext|>


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

use std::convert::From;
use std::error::Error;
use std::fmt::Display;

use super::Array;

/// An error returned when checking if the grid is well-sized and legal.
#[derive(Clone, Debug, Hash, PartialEq)]
pub enum GridError {
    /// The grid does not have the right size.
    ///
    /// (It should be square, of non-null, even size.)
    BadSize(GridSizeError),
    /// The grid is illegal, that is it infringes at least one of the rules.
    Illegal,
}

impl Display for GridError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            GridError::BadSize(ref err) => write!(f, "{}: {}", self.description(), err),
            GridError::Illegal => f.write_str(self.description()),
        }
    }
}

impl Error for GridError {
    fn description(&self) -> &str {
        match *self {
            GridError::BadSize(_) => "faulty grid size",
            GridError::Illegal => "grid is illegal",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GridError::BadSize(ref err) => Some(err),
            GridError::Illegal => None,
        }
    }
}

impl From<GridSizeError> for GridError {
    fn from(err: GridSizeError) -> Self {
        GridError::BadSize(err)
    }
}

/// An error returned when parsing a string to create a grid failed.
#[derive(Clone, Debug, Hash, PartialEq)]
pub enum GridParseError {
    /// A `Grid` cannot be created from this `Array`.
    CreationError(GridError, Array),
    /// At least one character other than `0`, `1`, `.` or '\n'
    /// was found in the string.
    UnexpectedCharacter,
}

impl Display for GridParseError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            GridParseError::CreationError(ref err, _) => write!(f, "{}: {}", self.description(), err),
            GridParseError::UnexpectedCharacter => f.write_str(self.description()),
        }
    }
}

impl Error for GridParseError {
    fn description(&self) -> &str {
        match *self {
            GridParseError::CreationError(_, _) => "could not create grid",
            GridParseError::UnexpectedCharacter => "found unexpected character(s)",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GridParseError::CreationError(ref err, _) => Some(err),
            GridParseError::UnexpectedCharacter => None,
        }
    }
}

/// An error returned when the grid is not properly sized.
#[derive(Clone, Debug, Hash, PartialEq)]
pub enum GridSizeError {
    /// The grid is empty.
    Empty,
    /// The grid is not a square.
    /// The field contains the line number that triggered the error.
    NotASquare(usize),
    /// The grid has an odd number of rows.
    OddRowNumber,
}

impl Display for GridSizeError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            GridSizeError::Empty => f.write_str(self.description()),
            GridSizeError::NotASquare(n) => write!(f, "{} (line {})", self.description(), n),
            GridSizeError::OddRowNumber => f.write_str(self.description()),
        }
    }
}

impl Error for GridSizeError {
    fn description(&self) -> &str {
        match *self {
            GridSizeError::Empty => "empty grid",
            GridSizeError::NotASquare(_) => "not a square",
            GridSizeError::OddRowNumber => "odd number of rows",
        }
    }
}
<commit_msg>remove unused derives on errors<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::convert::From;
use std::error::Error;
use std::fmt::Display;

use super::Array;

/// An error returned when checking if the grid is well-sized and legal.
#[derive(Debug)]
pub enum GridError {
    /// The grid does not have the right size.
    ///
    /// (It should be square, of non-null, even size.)
    BadSize(GridSizeError),
    /// The grid is illegal, that is it infringes at least one of the rules.
    Illegal,
}

impl Display for GridError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            GridError::BadSize(ref err) => write!(f, "{}: {}", self.description(), err),
            GridError::Illegal => f.write_str(self.description()),
        }
    }
}

impl Error for GridError {
    fn description(&self) -> &str {
        match *self {
            GridError::BadSize(_) => "faulty grid size",
            GridError::Illegal => "grid is illegal",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GridError::BadSize(ref err) => Some(err),
            GridError::Illegal => None,
        }
    }
}

impl From<GridSizeError> for GridError {
    fn from(err: GridSizeError) -> Self {
        GridError::BadSize(err)
    }
}

/// An error returned when parsing a string to create a grid failed.
#[derive(Debug)]
pub enum GridParseError {
    /// A `Grid` cannot be created from this `Array`.
    CreationError(GridError, Array),
    /// At least one character other than `0`, `1`, `.` or '\n'
    /// was found in the string.
    UnexpectedCharacter,
}

impl Display for GridParseError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            GridParseError::CreationError(ref err, _) => write!(f, "{}: {}", self.description(), err),
            GridParseError::UnexpectedCharacter => f.write_str(self.description()),
        }
    }
}

impl Error for GridParseError {
    fn description(&self) -> &str {
        match *self {
            GridParseError::CreationError(_, _) => "could not create grid",
            GridParseError::UnexpectedCharacter => "found unexpected character(s)",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GridParseError::CreationError(ref err, _) => Some(err),
            GridParseError::UnexpectedCharacter => None,
        }
    }
}

/// An error returned when the grid is not properly sized.
#[derive(Debug)]
pub enum GridSizeError {
    /// The grid is empty.
    Empty,
    /// The grid is not a square.
    /// The field contains the line number that triggered the error.
    NotASquare(usize),
    /// The grid has an odd number of rows.
    OddRowNumber,
}

impl Display for GridSizeError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            GridSizeError::Empty => f.write_str(self.description()),
            GridSizeError::NotASquare(n) => write!(f, "{} (line {})", self.description(), n),
            GridSizeError::OddRowNumber => f.write_str(self.description()),
        }
    }
}

impl Error for GridSizeError {
    fn description(&self) -> &str {
        match *self {
            GridSizeError::Empty => "empty grid",
            GridSizeError::NotASquare(_) => "not a square",
            GridSizeError::OddRowNumber => "odd number of rows",
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
use ::card::*;

#[test]
fn create_hand() {
    let mut deck = ::deck::Deck::new();
    let mut cards: Vec<::card::Card> = vec![];
    for _i in 0..5 {
        cards.push(deck.draw().unwrap());
    }
    let hand = ::hand::Hand::new(cards);

    assert_eq!(hand.cards.len(), 5);
}

#[test]
fn has_flush() {
    let a = Card::new(Value::Three, Suit::Hearts);
    let b = Card::new(Value::Six, Suit::Hearts);
    let c = Card::new(Value::Ten, Suit::Hearts);
    let d = Card::new(Value::Queen, Suit::Hearts);
    let e = Card::new(Value::Two, Suit::Hearts);
    let cards: Vec<Card> = vec![a, b, c, d, e];
    let hand: ::hand::Hand = ::hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), true);
}

#[test]
fn no_flush() {
    let a = Card::new(Value::Three, Suit::Hearts);
    let b = Card::new(Value::Six, Suit::Spades);
    let c = Card::new(Value::Ten, Suit::Hearts);
    let d = Card::new(Value::Queen, Suit::Hearts);
    let e = Card::new(Value::Two, Suit::Hearts);
    let cards: Vec<Card> = vec![a, b, c, d, e];
    let hand: ::hand::Hand = ::hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), false);
}

#[test]
fn high_card_raw_value() {

}
<commit_msg>Added unit tests for HighCard, OnePair, and TwoPair<commit_after>#[cfg(test)]
use ::{card, deck, hand};

#[test]
fn create_hand() {
    let mut deck = deck::Deck::new();
    let mut cards: Vec<card::Card> = vec![];
    for _i in 0..5 {
        cards.push(deck.draw().unwrap());
    }
    let hand = hand::Hand::new(cards);

    assert_eq!(hand.cards.len(), 5);
}

#[test]
fn has_flush() {
    let a = card::Card::new(card::Value::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Value::Six, card::Suit::Hearts);
    let c = card::Card::new(card::Value::Ten, card::Suit::Hearts);
    let d = card::Card::new(card::Value::Queen, card::Suit::Hearts);
    let e = card::Card::new(card::Value::Two, card::Suit::Hearts);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), true);
}

#[test]
fn no_flush() {
    let a = card::Card::new(card::Value::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Value::Six, card::Suit::Spades);
    let c = card::Card::new(card::Value::Ten, card::Suit::Hearts);
    let d = card::Card::new(card::Value::Queen, card::Suit::Hearts);
    let e = card::Card::new(card::Value::Two, card::Suit::Hearts);
    let cards: Vec<card::Card> = vec![a, b, c, d, e];
    let hand: hand::Hand = hand::Hand::new(cards);

    assert_eq!(hand.has_flush(), false);
}

#[test]
fn high_card_raw_value() {
    let a = card::Card::new(card::Value::Three, card::Suit::Hearts);
    let poker_hand = hand::PokerHand::HighCard(a);

    assert_eq!(poker_hand.raw_value(), 0);
}

#[test]
fn one_pair_raw_value() {
    let a = card::Card::new(card::Value::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Value::Three, card::Suit::Diamonds);
    let poker_hand = hand::PokerHand::OnePair((a, b));

    assert_eq!(poker_hand.raw_value(), 1);
}

#[test]
fn two_pair_raw_value() {
    let a = card::Card::new(card::Value::Three, card::Suit::Hearts);
    let b = card::Card::new(card::Value::Three, card::Suit::Diamonds);
    let c = card::Card::new(card::Value::King, card::Suit::Spades);
    let d = card::Card::new(card::Value::King, card::Suit::Hearts);
    let poker_hand = hand::PokerHand::TwoPair((a, b), (c, d));

    assert_eq!(poker_hand.raw_value(), 2);
}
<|endoftext|>


<commit_before>//! Bounded package merge algorithm, based on the paper
//! "A Fast and Space-Economical Algorithm for Length-Limited Coding
//! Jyrki Katajainen, Alistair Moffat, Andrew Turpin".

use std::iter;
use std::mem;
use std::ptr::{null, null_mut};

use libc::{c_void, size_t};

/// Nodes forming chains. Also used to represent leaves.
struct Node {
    /// Total weight (symbol count) of this chain.
    weight: usize,
    /// Previous node(s) of this chain, or 0 if none.
    tail: *mut Node,
    /// Leaf symbol index, or number of leaves before this chain.
    count: i32,
    /// Tracking for garbage collection.
    in_use: bool,
}

/// Memory pool for nodes.
struct NodePool {
    /// The pool.
    nodes: Vec<Node>,
    /// Index of a possibly free node in the pool.
    next: u32,
    /// Size of the memory pool.
    size: u32,
}

impl NodePool {
    fn new(pool_size: u32) -> NodePool {
        NodePool {
            nodes: (0..pool_size).map(|_| {
                Node {
                    weight: 0,
                    tail: null_mut(),
                    count: 0,
                    in_use: false,
                }
            }).collect(),
            next: 0,
            size: pool_size,
        }
    }
}
/// Initializes a chain node with the given values and marks it as in use.
unsafe fn init_node(weight: usize, count: i32, tail: *mut Node, node: *mut Node) {
    (*node).weight = weight;
    (*node).count = count;
    (*node).tail = tail;
    (*node).in_use = true;
}

/**
 * Finds a free location in the memory pool. Performs garbage collection if needed.
 * lists: If given, used to mark in-use nodes during garbage collection.
 * maxbits: Size of lists.
 * pool: Memory pool to get free node from.
 */
unsafe fn get_free_node(lists: Option<&Vec<[*mut Node; 2]>>,
                        maxbits: i32,
                        pool: &mut NodePool)
                        -> *mut Node {
    loop {
        if pool.next >= pool.size {
            // Garbage collection
            for i in 0..pool.size {
                pool.nodes[i as usize].in_use = false;
            }
            if let Some(lists) = lists {
                for i in 0..maxbits * 2 {
                    let mut node = lists[(i / 2) as usize][(i % 2) as usize];
                    while !node.is_null() {
                        (*node).in_use = true;
                        node = (*node).tail;
                    }
                }
            }
            pool.next = 0;
        }
        if !pool.nodes[pool.next as usize].in_use {
            break;
        }
        pool.next += 1;
    }
    let free_node = &mut pool.nodes[pool.next as usize];
    pool.next += 1;
    free_node
}

/**
 * Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
 * new chain is, depending on the weights, a leaf or a combination of two chains
 * from the previous list.
 * lists: The lists of chains.
 * maxbits: Number of lists.
 * leaves: The leaves, one per symbol.
 * numsymbols: Number of leaves.
 * pool: the node memory pool.
 * index: The index of the list in which a new chain or leaf is required.
 * final: Whether this is the last time this function is called. If it is then it
 *   is no more needed to recursively call self.
 */
unsafe fn boundary_pm(lists: &mut Vec<[*mut Node; 2]>,
                      maxbits: i32,
                      leaves: &[Node],
                      numsymbols: i32,
                      pool: &mut NodePool,
                      index: i32,
                      is_final: bool) {
    let lastcount = (*lists[index as usize][1]).count; // Count of last chain of list.

    if index == 0 && lastcount >= numsymbols {
        return;
    }

    let newchain = get_free_node(Some(&lists), maxbits, pool);
    let oldchain = lists[index as usize][1];

    // These are set up before the recursive calls below, so that there is a list
    // pointing to the new node, to let the garbage collection know it's in use.
    lists[index as usize][0] = oldchain;
    lists[index as usize][1] = newchain;

    if index == 0 {
        // New leaf node in list 0.
        init_node(leaves[lastcount as usize].weight,
                  lastcount + 1,
                  null_mut(),
                  newchain);
    } else {
        let sum = (*lists[(index - 1) as usize][0]).weight +
                  (*lists[(index - 1) as usize][1]).weight;
        if lastcount < numsymbols && sum > leaves[lastcount as usize].weight {
            // New leaf inserted in list, so count is incremented.
            init_node(leaves[lastcount as usize].weight,
                      lastcount + 1,
                      (*oldchain).tail,
                      newchain);
        } else {
            init_node(sum,
                      lastcount,
                      lists[(index - 1) as usize][1],
                      newchain);
            if !is_final {
                // Two lookahead chains of previous list used up, create new ones.
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
            }
        }
    }
}

/// Initializes each list with as lookahead chains the two leaves with lowest weights.
unsafe fn init_lists(pool: &mut NodePool,
                     leaves: &[Node],
                     maxbits: i32) -> Vec<[*mut Node; 2]> {
    let node0 = get_free_node(None, maxbits, pool);
    let node1 = get_free_node(None, maxbits, pool);
    init_node(leaves[0].weight, 1, null_mut(), node0);
    init_node(leaves[1].weight, 2, null_mut(), node1);
    iter::repeat([node0, node1]).take(maxbits as usize).collect()
}

/**
 * Converts result of boundary package-merge to the bitlengths. The result in the
 * last chain of the last list contains the amount of active leaves in each list.
 * chain: Chain to extract the bit length from (last chain from last list).
 */
unsafe fn extract_bit_lengths(chain: *const Node, leaves: &[Node], bitlengths: &mut [u32]) {
    let mut node = chain;
    while node != null() {
        for i in 0..(*node).count {
            bitlengths[leaves[i as usize].count as usize] =
                bitlengths[leaves[i as usize].count as usize] + 1;
        }
        node = (*node).tail;
    }
}

/// Comparator for sorting the leaves. Has the function signature for qsort.
extern "C" fn leaf_comparator(a: *const c_void, b: *const c_void) -> i32 {
    unsafe {
        let node_a: *const Node = a as *const Node;
        let node_b: *const Node = b as *const Node;
        (*node_a).weight as i32 - (*node_b).weight as i32
    }
}

#[link(name="c")]
extern {
    fn qsort(base: *mut c_void,
             nmemb: size_t,
             size: size_t,
             compar: extern "C" fn(*const c_void, *const c_void) -> i32);
}

pub unsafe fn length_limited_code_lengths(frequencies: &[usize],
                                          n: i32,
                                          maxbits: i32,
                                          bitlengths: &mut [u32])
                                          -> bool {
    // One leaf per symbol. Only numsymbols leaves will be used.
    let mut leaves: Vec<Node> = Vec::with_capacity(n as usize);

    // Initialize all bitlengths at 0.
    for i in 0..n {
        bitlengths[i as usize] = 0;
    }

    // Count used symbols and place them in the leaves.
    for i in 0..n {
        if frequencies[i as usize] != 0 {
            leaves.push(Node {
                weight: frequencies[i as usize],
                count: i, // Index of symbol this leaf represents.
                tail: null_mut(),
                in_use: false,
            });
        }
    }
    // Amount of symbols with frequency > 0.
    let numsymbols = leaves.len();

    // Check special cases and error conditions.
    if (1 << maxbits) < numsymbols {
        return true; // Error, too few maxbits to represent symbols.
    }
    if numsymbols == 0 {
        return false; // No symbols at all. OK.
    }
    if numsymbols == 1 {
        bitlengths[leaves[0].count as usize] = 1;
        return false; // Only one symbol, give it bitlength 1, not 0. OK.
    }

    // Sort the leaves from lightest to heaviest.
    qsort(leaves.as_mut_ptr() as *mut c_void,
          numsymbols as size_t,
          mem::size_of::<Node>() as size_t,
          leaf_comparator);

    // Initialize node memory pool.
    let mut pool = NodePool::new(2 * maxbits as u32 * (maxbits as u32 + 1));

    // Array of lists of chains. Each list requires only two lookahead chains at
    // a time, so each list is a array of two Node*'s.
    let mut lists: Vec<[*mut Node; 2]> = init_lists(&mut pool, &leaves, maxbits);

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each BoundaryPM run creates one.
    let num_boundary_pm_runs = 2 * numsymbols - 4;
    for i in 0..num_boundary_pm_runs {
        let is_final = i == num_boundary_pm_runs - 1;
        boundary_pm(&mut lists,
                    maxbits,
                    &leaves,
                    numsymbols as i32,
                    &mut pool,
                    maxbits - 1,
                    is_final);
    }

    extract_bit_lengths(lists[maxbits as usize - 1][1], &leaves, bitlengths);
    false // OK.
}

#[cfg(test)]
mod tests {
    use std::mem::size_of;
    use libc::{c_void, size_t};

    use super::qsort;

    extern "C" fn comparator(a: *const c_void, b: *const c_void) -> i32 {
        unsafe { *(a as *const i32) - *(b as *const i32) }
    }

    #[test]
    fn test_qsort() {
        unsafe {
            let mut a: [i32; 5] = [3, 2, 4, 1, 5];
            qsort(a.as_mut_ptr() as *mut c_void,
                  a.len() as size_t,
                  size_of::<i32>() as size_t,
                  comparator);
            assert_eq!(a, [1, 2, 3, 4, 5]);
        }
    }
}
<commit_msg>Use Option instead of null<commit_after>//! Bounded package merge algorithm, based on the paper
//! "A Fast and Space-Economical Algorithm for Length-Limited Coding
//! Jyrki Katajainen, Alistair Moffat, Andrew Turpin".

use std::iter;
use std::mem;

use libc::{c_void, size_t};

/// Nodes forming chains. Also used to represent leaves.
struct Node {
    /// Total weight (symbol count) of this chain.
    weight: usize,
    /// Previous node(s) of this chain, or 0 if none.
    tail: Option<*mut Node>,
    /// Leaf symbol index, or number of leaves before this chain.
    count: i32,
    /// Tracking for garbage collection.
    in_use: bool,
}

/// Memory pool for nodes.
struct NodePool {
    /// The pool.
    nodes: Vec<Node>,
    /// Index of a possibly free node in the pool.
    next: u32,
    /// Size of the memory pool.
    size: u32,
}

impl NodePool {
    fn new(pool_size: u32) -> NodePool {
        NodePool {
            nodes: (0..pool_size).map(|_| {
                Node {
                    weight: 0,
                    tail: None,
                    count: 0,
                    in_use: false,
                }
            }).collect(),
            next: 0,
            size: pool_size,
        }
    }
}
/// Initializes a chain node with the given values and marks it as in use.
unsafe fn init_node(weight: usize, count: i32, tail: Option<*mut Node>, node: *mut Node) {
    (*node).weight = weight;
    (*node).count = count;
    (*node).tail = tail;
    (*node).in_use = true;
}

/**
 * Finds a free location in the memory pool. Performs garbage collection if needed.
 * lists: If given, used to mark in-use nodes during garbage collection.
 * maxbits: Size of lists.
 * pool: Memory pool to get free node from.
 */
unsafe fn get_free_node(lists: Option<&Vec<[Option<*mut Node>; 2]>>,
                        maxbits: i32,
                        pool: &mut NodePool)
                        -> *mut Node {
    loop {
        if pool.next >= pool.size {
            // Garbage collection
            for i in 0..pool.size {
                pool.nodes[i as usize].in_use = false;
            }
            if let Some(lists) = lists {
                for i in 0..maxbits * 2 {
                    let mut node = lists[(i / 2) as usize][(i % 2) as usize];
                    while node.is_some() {
                        (*node.unwrap()).in_use = true;
                        node = (*node.unwrap()).tail;
                    }
                }
            }
            pool.next = 0;
        }
        if !pool.nodes[pool.next as usize].in_use {
            break;
        }
        pool.next += 1;
    }
    let free_node = &mut pool.nodes[pool.next as usize];
    pool.next += 1;
    free_node
}

/**
 * Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
 * new chain is, depending on the weights, a leaf or a combination of two chains
 * from the previous list.
 * lists: The lists of chains.
 * maxbits: Number of lists.
 * leaves: The leaves, one per symbol.
 * numsymbols: Number of leaves.
 * pool: the node memory pool.
 * index: The index of the list in which a new chain or leaf is required.
 * final: Whether this is the last time this function is called. If it is then it
 *   is no more needed to recursively call self.
 */
unsafe fn boundary_pm(lists: &mut Vec<[Option<*mut Node>; 2]>,
                      maxbits: i32,
                      leaves: &[Node],
                      numsymbols: i32,
                      pool: &mut NodePool,
                      index: i32,
                      is_final: bool) {
    let lastcount = (*lists[index as usize][1].unwrap()).count; // Count of last chain of list.

    if index == 0 && lastcount >= numsymbols {
        return;
    }

    let newchain = get_free_node(Some(&lists), maxbits, pool);
    let oldchain = lists[index as usize][1];

    // These are set up before the recursive calls below, so that there is a list
    // pointing to the new node, to let the garbage collection know it's in use.
    lists[index as usize][0] = oldchain;
    lists[index as usize][1] = Some(newchain);

    if index == 0 {
        // New leaf node in list 0.
        init_node(leaves[lastcount as usize].weight,
                  lastcount + 1,
                  None,
                  newchain);
    } else {
        let sum = (*lists[(index - 1) as usize][0].unwrap()).weight +
                  (*lists[(index - 1) as usize][1].unwrap()).weight;
        if lastcount < numsymbols && sum > leaves[lastcount as usize].weight {
            // New leaf inserted in list, so count is incremented.
            init_node(leaves[lastcount as usize].weight,
                      lastcount + 1,
                      (*oldchain.unwrap()).tail,
                      newchain);
        } else {
            init_node(sum,
                      lastcount,
                      lists[(index - 1) as usize][1],
                      newchain);
            if !is_final {
                // Two lookahead chains of previous list used up, create new ones.
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
            }
        }
    }
}

/// Initializes each list with as lookahead chains the two leaves with lowest weights.
unsafe fn init_lists(pool: &mut NodePool,
                     leaves: &[Node],
                     maxbits: i32) -> Vec<[Option<*mut Node>; 2]> {
    let node0 = get_free_node(None, maxbits, pool);
    let node1 = get_free_node(None, maxbits, pool);
    init_node(leaves[0].weight, 1, None, node0);
    init_node(leaves[1].weight, 2, None, node1);
    iter::repeat([Some(node0), Some(node1)]).take(maxbits as usize).collect()
}

/**
 * Converts result of boundary package-merge to the bitlengths. The result in the
 * last chain of the last list contains the amount of active leaves in each list.
 * chain: Chain to extract the bit length from (last chain from last list).
 */
unsafe fn extract_bit_lengths(chain: Option<*mut Node>, leaves: &[Node], bitlengths: &mut [u32]) {
    let mut node = chain;
    while node.is_some() {
        for i in 0..(*node.unwrap()).count {
            bitlengths[leaves[i as usize].count as usize] =
                bitlengths[leaves[i as usize].count as usize] + 1;
        }
        node = (*node.unwrap()).tail;
    }
}

/// Comparator for sorting the leaves. Has the function signature for qsort.
extern "C" fn leaf_comparator(a: *const c_void, b: *const c_void) -> i32 {
    unsafe {
        let node_a: *const Node = a as *const Node;
        let node_b: *const Node = b as *const Node;
        (*node_a).weight as i32 - (*node_b).weight as i32
    }
}

#[link(name="c")]
extern {
    fn qsort(base: *mut c_void,
             nmemb: size_t,
             size: size_t,
             compar: extern "C" fn(*const c_void, *const c_void) -> i32);
}

pub unsafe fn length_limited_code_lengths(frequencies: &[usize],
                                          n: i32,
                                          maxbits: i32,
                                          bitlengths: &mut [u32])
                                          -> bool {
    // One leaf per symbol. Only numsymbols leaves will be used.
    let mut leaves: Vec<Node> = Vec::with_capacity(n as usize);

    // Initialize all bitlengths at 0.
    for i in 0..n {
        bitlengths[i as usize] = 0;
    }

    // Count used symbols and place them in the leaves.
    for i in 0..n {
        if frequencies[i as usize] != 0 {
            leaves.push(Node {
                weight: frequencies[i as usize],
                count: i, // Index of symbol this leaf represents.
                tail: None,
                in_use: false,
            });
        }
    }
    // Amount of symbols with frequency > 0.
    let numsymbols = leaves.len();

    // Check special cases and error conditions.
    if (1 << maxbits) < numsymbols {
        return true; // Error, too few maxbits to represent symbols.
    }
    if numsymbols == 0 {
        return false; // No symbols at all. OK.
    }
    if numsymbols == 1 {
        bitlengths[leaves[0].count as usize] = 1;
        return false; // Only one symbol, give it bitlength 1, not 0. OK.
    }

    // Sort the leaves from lightest to heaviest.
    qsort(leaves.as_mut_ptr() as *mut c_void,
          numsymbols as size_t,
          mem::size_of::<Node>() as size_t,
          leaf_comparator);

    // Initialize node memory pool.
    let mut pool = NodePool::new(2 * maxbits as u32 * (maxbits as u32 + 1));

    // Array of lists of chains. Each list requires only two lookahead chains at
    // a time, so each list is a array of two Node*'s.
    let mut lists: Vec<[Option<*mut Node>; 2]> = init_lists(&mut pool, &leaves, maxbits);

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each BoundaryPM run creates one.
    let num_boundary_pm_runs = 2 * numsymbols - 4;
    for i in 0..num_boundary_pm_runs {
        let is_final = i == num_boundary_pm_runs - 1;
        boundary_pm(&mut lists,
                    maxbits,
                    &leaves,
                    numsymbols as i32,
                    &mut pool,
                    maxbits - 1,
                    is_final);
    }

    extract_bit_lengths(lists[maxbits as usize - 1][1], &leaves, bitlengths);
    false // OK.
}

#[cfg(test)]
mod tests {
    use std::mem::size_of;
    use libc::{c_void, size_t};

    use super::qsort;

    extern "C" fn comparator(a: *const c_void, b: *const c_void) -> i32 {
        unsafe { *(a as *const i32) - *(b as *const i32) }
    }

    #[test]
    fn test_qsort() {
        unsafe {
            let mut a: [i32; 5] = [3, 2, 4, 1, 5];
            qsort(a.as_mut_ptr() as *mut c_void,
                  a.len() as size_t,
                  size_of::<i32>() as size_t,
                  comparator);
            assert_eq!(a, [1, 2, 3, 4, 5]);
        }
    }
}
<|endoftext|>