<commit_before>use crate::StrError;

/// Implements the shape(N) time scalar(S) time gradient(G) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠       →
/// Kᵐⁿ = │ NBᵐ s Gⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_nsg() -> Result<(), StrError> {
    Err("mat_coupling_nsg: TODO")
}

/// Implements the gradient(G) time tensor(T) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ GBᵐ ⋅ T Nⁿ dΩ
///       ⌡       ▔
///       Ωₑ
/// ```
pub fn mat_coupling_gtn() -> Result<(), StrError> {
    Err("mat_coupling_gtn: TODO")
}

/// Implements the shape(N) time vector(V) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠    →
/// Kᵐⁿ = │ Nᵐ v NBⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_nvn() -> Result<(), StrError> {
    Err("mat_coupling_nvn: TODO")
}

/// Implements the gradient(G) time scalar(S) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ Gᵐ s NBⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_gsn() -> Result<(), StrError> {
    Err("mat_coupling_gsn: TODO")
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{mat_coupling_gsn, mat_coupling_gtn, mat_coupling_nsg, mat_coupling_nvn};

    #[test]
    fn functions_return_todo() {
        assert_eq!(mat_coupling_nsg().err(), Some("mat_coupling_nsg: TODO"));
        assert_eq!(mat_coupling_gtn().err(), Some("mat_coupling_gtn: TODO"));
        assert_eq!(mat_coupling_nvn().err(), Some("mat_coupling_nvn: TODO"));
        assert_eq!(mat_coupling_gsn().err(), Some("mat_coupling_gsn: TODO"));
    }
}
<commit_msg>[wip] Impl coupled integ functions<commit_after>use super::IntegPointData;
use crate::shapes::Scratchpad;
use crate::StrError;
use russell_lab::Matrix;

/// Implements the shape(Nb) time scalar(S) time gradient(G) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠       →
/// Kᵐⁿ = │ Nbᵐ s Gⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
///        nip-1     →     →       →       →
/// Kᵐⁿⱼ ≈   Σ   Nbᵐ(ιᵖ) s(ιᵖ) Gⁿⱼ(ιᵖ) |J|(ιᵖ) wᵖ
///         p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌                                        ┐
///     | K⁰⁰₀ K⁰⁰₁ K⁰¹₀ K⁰¹₁ K⁰²₀ K⁰²₁ ··· K⁰ⁿⱼ |  ⟸  ii0
///     | K¹⁰₀ K¹⁰₁ K¹¹₀ K¹¹₁ K¹²₀ K¹²₁ ··· K¹ⁿⱼ |
/// K = | K²⁰₀ K²⁰₁ K²¹₀ K²¹₁ K²²₀ K²²₁ ··· K²ⁿⱼ |
///     |  ··   ··   ··   ··   ··   ··  ···  ··  |
///     | Kᵐ⁰₀ Kᵐ⁰₁ Kᵐ¹₀ Kᵐ¹₁ Kᵐ²₀ Kᵐ²₁ ··· Kᵐⁿⱼ |  ⟸  ii
///     └                                        ┘
///        ⇑                                  ⇑
///       jj0                                 jj := j + n ⋅ space_ndim
///
/// n = jj / space_ndim
/// j = jj % space_ndim
/// ```
///
/// * `kk` -- A matrix containing all `Kᵐⁿⱼ` values, one after another, and sequentially placed as shown
///   above (in 2D). `m` and `n` are the indices of the node and `j` corresponds to `space_ndim`.
///   The dimensions must be `nrow(K) ≥ ii0 + nnode` and `ncol(K) ≥ jj0 + nnode ⋅ space_ndim`.
/// * `pad_b` -- (to compute Nb). Some members of the scratchpad will be modified.
/// * `pad` -- Some members of the scratchpad will be modified.
///
/// # Input
///
/// * `ii0` -- Stride marking the first row in the output matrix where to add components.
/// * `jj0` -- Stride marking the first column in the output matrix where to add components.
/// * `clear_kk` -- Fills `kk` matrix with zeros, otherwise accumulate values into `kk`
/// * `ips` -- Integration points (n_integ_point)
/// * `fn_s` -- Function `f(p)` that computes `s(x(ιᵖ))` with `0 ≤ p ≤ n_integ_point`
///
/// # Warning and notes
///
/// The two [crate::shapes::Scratchpad]s mut be compatible with `pad_b` being the lower-order version of `pad`.
/// For example, if `pad` corresponds to `Qua8`, then `pad_b` must be a `Qua4`. Otherwise, **calculation errors may occur**.
///
/// Note: The determinant of the Jacobian is calculated for `pad`; i.e., `pad` is the **driver** of the calculations.
/// Also, the number of integration points must be consider the number of nodes of `pad` and the expected order of the whole integrand.
pub fn mat_coupling_nbsg<F>(
    kk: &mut Matrix,
    pad_b: &mut Scratchpad,
    pad: &mut Scratchpad,
    ii0: usize,
    jj0: usize,
    clear_kk: bool,
    ips: IntegPointData,
    fn_s: F,
) -> Result<(), StrError>
where
    F: Fn(usize) -> Result<f64, StrError>,
{
    // check
    let nnode = pad.interp.dim();
    let space_ndim = pad.xmax.len();
    let (nrow_kk, ncol_kk) = kk.dims();
    if nrow_kk < ii0 + nnode {
        return Err("nrow(K) must be ≥ ii0 + nnode");
    }
    if ncol_kk < jj0 + nnode * space_ndim {
        return Err("ncol(K) must be ≥ jj0 + nnode ⋅ space_ndim");
    }

    // clear output matrix
    if clear_kk {
        kk.fill(0.0);
    }

    // loop over integration points
    for p in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[p];
        let weight = ips[p][3];

        // calculate interpolation functions and Jacobian
        (pad_b.fn_interp)(&mut pad_b.interp, iota);
        let det_jac = pad.calc_gradient(iota)?;

        // calculate s
        let s = fn_s(p)?;

        // add contribution to K matrix
        let val = s * det_jac * weight;
        let nnb = &pad_b.interp;
        let g = &pad.gradient;
        if space_ndim == 2 {
            for m in 0..nnode {
                for n in 0..nnode {
                    kk[ii0 + m][jj0 + 0 + n * 2] += nnb[m] * val * g[n][0];
                    kk[ii0 + m][jj0 + 1 + n * 2] += nnb[m] * val * g[n][1];
                }
            }
        } else {
            for m in 0..nnode {
                for n in 0..nnode {
                    kk[ii0 + m][jj0 + 0 + n * 3] += nnb[m] * val * g[n][0];
                    kk[ii0 + m][jj0 + 1 + n * 3] += nnb[m] * val * g[n][1];
                    kk[ii0 + m][jj0 + 2 + n * 3] += nnb[m] * val * g[n][2];
                }
            }
        }
    }
    Ok(())
}

/// Implements the gradient(G) time tensor(T) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ GBᵐ ⋅ T Nⁿ dΩ
///       ⌡       ▔
///       Ωₑ
/// ```
pub fn mat_coupling_gtn() -> Result<(), StrError> {
    Err("mat_coupling_gtn: TODO")
}

/// Implements the shape(N) time vector(V) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠    →
/// Kᵐⁿ = │ Nᵐ v NBⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_nvn() -> Result<(), StrError> {
    Err("mat_coupling_nvn: TODO")
}

/// Implements the gradient(G) time scalar(S) time shape(Nb) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ Gᵐ s Nbⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
///        nip-1     →     →       →       →
/// Kᵐⁿᵢ ≈   Σ   Gᵐᵢ(ιᵖ) s(ιᵖ) Nbⁿ(ιᵖ) |J|(ιᵖ) wᵖ
///         p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌                         ┐
///     | K⁰⁰₀ K⁰¹₀ K⁰²₀ ··· K⁰ⁿ₀ |  ⟸  ii0
///     | K⁰⁰₁ K⁰¹₁ K⁰²₁ ··· K⁰ⁿ₁ |
///     | K¹⁰₀ K¹¹₀ K¹²₀ ··· K¹ⁿ₀ |
/// K = | K¹⁰₁ K¹¹₁ K¹²₁ ··· K¹ⁿ₁ |
///     | K²⁰₀ K²¹₀ K²²₀ ··· K²ⁿ₀ |
///     | K²⁰₁ K²¹₁ K²²₁ ··· K²ⁿ₁ |
///     |  ···  ···  ··· ···  ··· |
///     | Kᵐ⁰ᵢ Kᵐ¹ᵢ Kᵐ²ᵢ ··· Kᵐⁿᵢ |  ⟸  ii := i + m ⋅ space_ndim
///     └                         ┘
///        ⇑                  ⇑
///       jj0                 jj
///
/// m = ii / space_ndim
/// i = ii % space_ndim
/// ```
///
/// * `kk` -- A matrix containing all `Kᵐⁿᵢ` values, one after another, and sequentially placed as shown
///   above (in 2D). `m` and `n` are the indices of the node and `i` corresponds to `space_ndim`.
///   The dimensions must be `nrow(K) ≥ ii0 + nnode ⋅ space_ndim` and `ncol(K) ≥ jj0 + nnode`.
/// * `pad` -- Some members of the scratchpad will be modified.
/// * `pad_b` -- (to compute Nb). Some members of the scratchpad will be modified.
///
/// # Input
///
/// * `ii0` -- Stride marking the first row in the output matrix where to add components.
/// * `jj0` -- Stride marking the first column in the output matrix where to add components.
/// * `clear_kk` -- Fills `kk` matrix with zeros, otherwise accumulate values into `kk`
/// * `ips` -- Integration points (n_integ_point)
/// * `fn_s` -- Function `f(p)` that computes `s(x(ιᵖ))` with `0 ≤ p ≤ n_integ_point`
///
/// # Warning and notes
///
/// The two [crate::shapes::Scratchpad]s mut be compatible with `pad_b` being the lower-order version of `pad`.
/// For example, if `pad` corresponds to `Qua8`, then `pad_b` must be a `Qua4`. Otherwise, **calculation errors may occur**.
///
/// Note: The determinant of the Jacobian is calculated for `pad`; i.e., `pad` is the **driver** of the calculations.
/// Also, the number of integration points must be consider the number of nodes of `pad` and the expected order of the whole integrand.
pub fn mat_coupling_gsnb<F>(
    kk: &mut Matrix,
    pad: &mut Scratchpad,
    pad_b: &mut Scratchpad,
    ii0: usize,
    jj0: usize,
    clear_kk: bool,
    ips: IntegPointData,
    fn_s: F,
) -> Result<(), StrError>
where
    F: Fn(usize) -> Result<f64, StrError>,
{
    // check
    let nnode = pad.interp.dim();
    let space_ndim = pad.xmax.len();
    let (nrow_kk, ncol_kk) = kk.dims();
    if nrow_kk < ii0 + nnode * space_ndim {
        return Err("nrow(K) must be ≥ ii0 + nnode ⋅ space_ndim");
    }
    if ncol_kk < jj0 + nnode {
        return Err("ncol(K) must be ≥ jj0 + nnode");
    }

    // clear output matrix
    if clear_kk {
        kk.fill(0.0);
    }

    // loop over integration points
    for p in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[p];
        let weight = ips[p][3];

        // calculate interpolation functions and Jacobian
        (pad_b.fn_interp)(&mut pad_b.interp, iota);
        let det_jac = pad.calc_gradient(iota)?;

        // calculate s
        let s = fn_s(p)?;

        // add contribution to K matrix
        let val = s * det_jac * weight;
        let g = &pad.gradient;
        let nnb = &pad_b.interp;
        if space_ndim == 2 {
            for m in 0..nnode {
                for n in 0..nnode {
                    kk[ii0 + 0 + m * 2][jj0 + n] += g[m][0] * val * nnb[n];
                    kk[ii0 + 1 + m * 2][jj0 + n] += g[m][1] * val * nnb[n];
                }
            }
        } else {
            for m in 0..nnode {
                for n in 0..nnode {
                    kk[ii0 + 0 + m * 3][jj0 + n] += g[m][0] * val * nnb[n];
                    kk[ii0 + 1 + m * 3][jj0 + n] += g[m][1] * val * nnb[n];
                    kk[ii0 + 2 + m * 3][jj0 + n] += g[m][2] * val * nnb[n];
                }
            }
        }
    }
    Ok(())
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{mat_coupling_gsnb, mat_coupling_gtn, mat_coupling_nbsg, mat_coupling_nvn};

    #[test]
    fn functions_return_todo() {
        assert_eq!(mat_coupling_gtn().err(), Some("mat_coupling_gtn: TODO"));
        assert_eq!(mat_coupling_nvn().err(), Some("mat_coupling_nvn: TODO"));
    }
}
<|endoftext|>


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

//! Parser and serializer for the [`application/x-www-form-urlencoded` syntax](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

use encoding::EncodingOverride;
use percent_encoding::{percent_encode_byte, percent_decode};
use std::borrow::{Borrow, Cow};
use std::str;

/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// The names and values are percent-decoded. For instance, `%23first=%25try%25` will be
/// converted to `[("#first", "%try%")]`.
#[inline]
pub fn parse(input: &[u8]) -> Parse {
    Parse {
        input: input,
        encoding: EncodingOverride::utf8(),
    }
}

/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// This function is only available if the `query_encoding`
/// [feature](http://doc.crates.io/manifest.html#the-features-section]) is enabled.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is decoded as
///    after percent-decoding. Defaults to UTF-8.
///    `EncodingRef` is defined in [rust-encoding](https://github.com/lifthrasiir/rust-encoding).
/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
#[cfg(feature = "query_encoding")]
pub fn parse_with_encoding<'a>(input: &'a [u8],
                               encoding_override: Option<::encoding::EncodingRef>,
                               use_charset: bool)
                               -> Result<Parse<'a>, ()> {
    use std::ascii::AsciiExt;

    let mut encoding = EncodingOverride::from_opt_encoding(encoding_override);
    if !(encoding.is_utf8() || input.is_ascii()) {
        return Err(())
    }
    if use_charset {
        for sequence in input.split(|&b| b == b'&') {
            // No '+' in "_charset_" to replace with ' '.
            if sequence.starts_with(b"_charset_=") {
                let value = &sequence[b"_charset_=".len()..];
                // Skip replacing '+' with ' ' in value since no encoding label contains either:
                // https://encoding.spec.whatwg.org/#names-and-labels
                if let Some(e) = EncodingOverride::lookup(value) {
                    encoding = e;
                    break
                }
            }
        }
    }
    Ok(Parse {
        input: input,
        encoding: encoding,
    })
}

/// The return type of `parse()`.
#[derive(Copy, Clone, Debug)]
pub struct Parse<'a> {
    input: &'a [u8],
    encoding: EncodingOverride,
}

impl<'a> Iterator for Parse<'a> {
    type Item = (Cow<'a, str>, Cow<'a, str>);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.input.is_empty() {
                return None
            }
            let mut split2 = self.input.splitn(2, |&b| b == b'&');
            let sequence = split2.next().unwrap();
            self.input = split2.next().unwrap_or(&[][..]);
            if sequence.is_empty() {
                continue
            }
            let mut split2 = sequence.splitn(2, |&b| b == b'=');
            let name = split2.next().unwrap();
            let value = split2.next().unwrap_or(&[][..]);
            return Some((
                decode(name, self.encoding),
                decode(value, self.encoding),
            ))
        }
    }
}

fn decode(input: &[u8], encoding: EncodingOverride) -> Cow<str> {
    let replaced = replace_plus(input);
    encoding.decode(match percent_decode(&replaced).if_any() {
        Some(vec) => Cow::Owned(vec),
        None => replaced,
    })
}

/// Replace b'+' with b' '
fn replace_plus(input: &[u8]) -> Cow<[u8]> {
    match input.iter().position(|&b| b == b'+') {
        None => Cow::Borrowed(input),
        Some(first_position) => {
            let mut replaced = input.to_owned();
            replaced[first_position] = b' ';
            for byte in &mut replaced[first_position + 1..] {
                if *byte == b'+' {
                    *byte = b' ';
                }
            }
            Cow::Owned(replaced)
        }
    }
}

impl<'a> Parse<'a> {
    /// Return a new iterator that yields pairs of `String` instead of pairs of `Cow<str>`.
    pub fn into_owned(self) -> ParseIntoOwned<'a> {
        ParseIntoOwned { inner: self }
    }
}

/// Like `Parse`, but yields pairs of `String` instead of pairs of `Cow<str>`.
#[derive(Debug)]
pub struct ParseIntoOwned<'a> {
    inner: Parse<'a>
}

impl<'a> Iterator for ParseIntoOwned<'a> {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|(k, v)| (k.into_owned(), v.into_owned()))
    }
}

/// The [`application/x-www-form-urlencoded` byte serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer).
///
/// Return an iterator of `&str` slices.
pub fn byte_serialize(input: &[u8]) -> ByteSerialize {
    ByteSerialize {
        bytes: input,
    }
}

/// Return value of `byte_serialize()`.
#[derive(Debug)]
pub struct ByteSerialize<'a> {
    bytes: &'a [u8],
}

fn byte_serialized_unchanged(byte: u8) -> bool {
    matches!(byte, b'*' | b'-' | b'.' | b'0' ... b'9' | b'A' ... b'Z' | b'_' | b'a' ... b'z')
}

impl<'a> Iterator for ByteSerialize<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some((&first, tail)) = self.bytes.split_first() {
            if !byte_serialized_unchanged(first) {
                self.bytes = tail;
                return Some(if first == b' ' { "+" } else { percent_encode_byte(first) })
            }
            let position = tail.iter().position(|&b| !byte_serialized_unchanged(b));
            let (unchanged_slice, remaining) = match position {
                // 1 for first_byte + i unchanged in tail
                Some(i) => self.bytes.split_at(1 + i),
                None => (self.bytes, &[][..]),
            };
            self.bytes = remaining;
            Some(unsafe { str::from_utf8_unchecked(unchanged_slice) })
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.bytes.is_empty() {
            (0, Some(0))
        } else {
            (1, Some(self.bytes.len()))
        }
    }
}

/// The [`application/x-www-form-urlencoded` serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-serializer).
#[derive(Debug)]
pub struct Serializer<T: Target> {
    target: Option<T>,
    start_position: usize,
    encoding: EncodingOverride,
}

pub trait Target {
    fn as_mut_string(&mut self) -> &mut String;
    fn finish(self) -> Self::Finished;
    type Finished;
}

impl Target for String {
    fn as_mut_string(&mut self) -> &mut String { self }
    fn finish(self) -> Self { self }
    type Finished = Self;
}

impl<'a> Target for &'a mut String {
    fn as_mut_string(&mut self) -> &mut String { &mut **self }
    fn finish(self) -> Self { self }
    type Finished = Self;
}

// `as_mut_string` string here exposes the internal serialization of an `Url`,
// which should not be exposed to users.
// We achieve that by not giving users direct access to `UrlQuery`:
// * Its fields are private
//   (and so can not be constructed with struct literal syntax outside of this crate),
// * It has no constructor
// * It is only visible (on the type level) to users in the return type of
//   `Url::query_pairs_mut` which is `Serializer<UrlQuery>`
// * `Serializer` keeps its target in a private field
// * Unlike in other `Target` impls, `UrlQuery::finished` does not return `Self`.
impl<'a> Target for ::UrlQuery<'a> {
    fn as_mut_string(&mut self) -> &mut String { &mut self.url.serialization }
    fn finish(self) -> &'a mut ::Url { self.url }
    type Finished = &'a mut ::Url;
}

impl<T: Target> Serializer<T> {
    /// Create a new `application/x-www-form-urlencoded` serializer for the given target.
    ///
    /// If the target is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn new(target: T) -> Self {
        Self::for_suffix(target, 0)
    }

    /// Create a new `application/x-www-form-urlencoded` serializer
    /// for a suffix of the given target.
    ///
    /// If that suffix is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn for_suffix(mut target: T, start_position: usize) -> Self {
        &target.as_mut_string()[start_position..];  // Panic if out of bounds
        Serializer {
            target: Some(target),
            start_position: start_position,
            encoding: EncodingOverride::utf8(),
        }
    }

    /// Remove any existing name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn clear(&mut self) -> &mut Self {
        string(&mut self.target).truncate(self.start_position);
        self
    }

    /// Set the character encoding to be used for names and values before percent-encoding.
    #[cfg(feature = "query_encoding")]
    pub fn encoding_override(&mut self, new: Option<::encoding::EncodingRef>) -> &mut Self {
        self.encoding = EncodingOverride::from_opt_encoding(new).to_output_encoding();
        self
    }

    /// Serialize and append a name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
        append_pair(string(&mut self.target), self.start_position, self.encoding, name, value);
        self
    }

    /// Serialize and append a number of name/value pairs.
    ///
    /// This simply calls `append_pair` repeatedly.
    /// This can be more convenient, so the user doesn’t need to introduce a block
    /// to limit the scope of `Serializer`’s borrow of its string.
    ///
    /// Panics if called after `.finish()`.
    pub fn extend_pairs<I, K, V>(&mut self, iter: I) -> &mut Self
    where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
        {
            let string = string(&mut self.target);
            for pair in iter {
                let &(ref k, ref v) = pair.borrow();
                append_pair(string, self.start_position, self.encoding, k.as_ref(), v.as_ref());
            }
        }
        self
    }

    /// Add a name/value pair whose name is `_charset_`
    /// and whose value is the character encoding’s name.
    /// (See the `encoding_override()` method.)
    ///
    /// Panics if called after `.finish()`.
    #[cfg(feature = "query_encoding")]
    pub fn append_charset(&mut self) -> &mut Self {
        {
            let string = string(&mut self.target);
            append_separator_if_needed(string, self.start_position);
            string.push_str("_charset_=");
            string.push_str(self.encoding.name());
        }
        self
    }

    /// If this serializer was constructed with a string, take and return that string.
    ///
    /// ```rust
    /// use url::form_urlencoded;
    /// let encoded: String = form_urlencoded::Serializer::new(String::new())
    ///     .append_pair("foo", "bar & baz")
    ///     .append_pair("saison", "Été+hiver")
    ///     .finish();
    /// assert_eq!(encoded, "foo=bar+%26+baz&saison=%C3%89t%C3%A9%2Bhiver");
    /// ```
    ///
    /// Panics if called more than once.
    pub fn finish(&mut self) -> T::Finished {
        self.target.take().expect("url::form_urlencoded::Serializer double finish").finish()
    }
}

fn append_separator_if_needed(string: &mut String, start_position: usize) {
    if string.len() > start_position {
        string.push('&')
    }
}

fn string<T: Target>(target: &mut Option<T>) -> &mut String {
    target.as_mut().expect("url::form_urlencoded::Serializer finished").as_mut_string()
}

fn append_pair(string: &mut String, start_position: usize, encoding: EncodingOverride,
               name: &str, value: &str) {
    append_separator_if_needed(string, start_position);
    string.extend(byte_serialize(&encoding.encode(name.into())));
    string.push('=');
    string.extend(byte_serialize(&encoding.encode(value.into())));
}
<commit_msg>Remove unnecessary bounds checking in a couple places.<commit_after>// Copyright 2013-2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parser and serializer for the [`application/x-www-form-urlencoded` syntax](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

use encoding::EncodingOverride;
use percent_encoding::{percent_encode_byte, percent_decode};
use std::borrow::{Borrow, Cow};
use std::str;

/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// The names and values are percent-decoded. For instance, `%23first=%25try%25` will be
/// converted to `[("#first", "%try%")]`.
#[inline]
pub fn parse(input: &[u8]) -> Parse {
    Parse {
        input: input,
        encoding: EncodingOverride::utf8(),
    }
}

/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// This function is only available if the `query_encoding`
/// [feature](http://doc.crates.io/manifest.html#the-features-section]) is enabled.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is decoded as
///    after percent-decoding. Defaults to UTF-8.
///    `EncodingRef` is defined in [rust-encoding](https://github.com/lifthrasiir/rust-encoding).
/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
#[cfg(feature = "query_encoding")]
pub fn parse_with_encoding<'a>(input: &'a [u8],
                               encoding_override: Option<::encoding::EncodingRef>,
                               use_charset: bool)
                               -> Result<Parse<'a>, ()> {
    use std::ascii::AsciiExt;

    let mut encoding = EncodingOverride::from_opt_encoding(encoding_override);
    if !(encoding.is_utf8() || input.is_ascii()) {
        return Err(())
    }
    if use_charset {
        for sequence in input.split(|&b| b == b'&') {
            // No '+' in "_charset_" to replace with ' '.
            if sequence.starts_with(b"_charset_=") {
                let value = unsafe { &sequence.get_unchecked(b"_charset_=".len()..) };
                // Skip replacing '+' with ' ' in value since no encoding label contains either:
                // https://encoding.spec.whatwg.org/#names-and-labels
                if let Some(e) = EncodingOverride::lookup(value) {
                    encoding = e;
                    break
                }
            }
        }
    }
    Ok(Parse {
        input: input,
        encoding: encoding,
    })
}

/// The return type of `parse()`.
#[derive(Copy, Clone, Debug)]
pub struct Parse<'a> {
    input: &'a [u8],
    encoding: EncodingOverride,
}

impl<'a> Iterator for Parse<'a> {
    type Item = (Cow<'a, str>, Cow<'a, str>);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.input.is_empty() {
                return None
            }
            let mut split2 = self.input.splitn(2, |&b| b == b'&');
            let sequence = split2.next().unwrap();
            self.input = split2.next().unwrap_or(&[][..]);
            if sequence.is_empty() {
                continue
            }
            let mut split2 = sequence.splitn(2, |&b| b == b'=');
            let name = split2.next().unwrap();
            let value = split2.next().unwrap_or(&[][..]);
            return Some((
                decode(name, self.encoding),
                decode(value, self.encoding),
            ))
        }
    }
}

fn decode(input: &[u8], encoding: EncodingOverride) -> Cow<str> {
    let replaced = replace_plus(input);
    encoding.decode(match percent_decode(&replaced).if_any() {
        Some(vec) => Cow::Owned(vec),
        None => replaced,
    })
}

/// Replace b'+' with b' '
fn replace_plus(input: &[u8]) -> Cow<[u8]> {
    match input.iter().position(|&b| b == b'+') {
        None => Cow::Borrowed(input),
        Some(first_position) => {
            let mut replaced = input.to_owned();
            unsafe {
                *replaced.get_unchecked_mut(first_position) = b' ';
                for byte in replaced.get_unchecked_mut(first_position + 1..) {
                    if *byte == b'+' {
                        *byte = b' ';
                    }
                }
            }
            Cow::Owned(replaced)
        }
    }
}

impl<'a> Parse<'a> {
    /// Return a new iterator that yields pairs of `String` instead of pairs of `Cow<str>`.
    pub fn into_owned(self) -> ParseIntoOwned<'a> {
        ParseIntoOwned { inner: self }
    }
}

/// Like `Parse`, but yields pairs of `String` instead of pairs of `Cow<str>`.
#[derive(Debug)]
pub struct ParseIntoOwned<'a> {
    inner: Parse<'a>
}

impl<'a> Iterator for ParseIntoOwned<'a> {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|(k, v)| (k.into_owned(), v.into_owned()))
    }
}

/// The [`application/x-www-form-urlencoded` byte serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer).
///
/// Return an iterator of `&str` slices.
pub fn byte_serialize(input: &[u8]) -> ByteSerialize {
    ByteSerialize {
        bytes: input,
    }
}

/// Return value of `byte_serialize()`.
#[derive(Debug)]
pub struct ByteSerialize<'a> {
    bytes: &'a [u8],
}

fn byte_serialized_unchanged(byte: u8) -> bool {
    matches!(byte, b'*' | b'-' | b'.' | b'0' ... b'9' | b'A' ... b'Z' | b'_' | b'a' ... b'z')
}

impl<'a> Iterator for ByteSerialize<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some((&first, tail)) = self.bytes.split_first() {
            if !byte_serialized_unchanged(first) {
                self.bytes = tail;
                return Some(if first == b' ' { "+" } else { percent_encode_byte(first) })
            }
            let position = tail.iter().position(|&b| !byte_serialized_unchanged(b));
            let (unchanged_slice, remaining) = match position {
                // 1 for first_byte + i unchanged in tail
                Some(i) => self.bytes.split_at(1 + i),
                None => (self.bytes, &[][..]),
            };
            self.bytes = remaining;
            Some(unsafe { str::from_utf8_unchecked(unchanged_slice) })
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.bytes.is_empty() {
            (0, Some(0))
        } else {
            (1, Some(self.bytes.len()))
        }
    }
}

/// The [`application/x-www-form-urlencoded` serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-serializer).
#[derive(Debug)]
pub struct Serializer<T: Target> {
    target: Option<T>,
    start_position: usize,
    encoding: EncodingOverride,
}

pub trait Target {
    fn as_mut_string(&mut self) -> &mut String;
    fn finish(self) -> Self::Finished;
    type Finished;
}

impl Target for String {
    fn as_mut_string(&mut self) -> &mut String { self }
    fn finish(self) -> Self { self }
    type Finished = Self;
}

impl<'a> Target for &'a mut String {
    fn as_mut_string(&mut self) -> &mut String { &mut **self }
    fn finish(self) -> Self { self }
    type Finished = Self;
}

// `as_mut_string` string here exposes the internal serialization of an `Url`,
// which should not be exposed to users.
// We achieve that by not giving users direct access to `UrlQuery`:
// * Its fields are private
//   (and so can not be constructed with struct literal syntax outside of this crate),
// * It has no constructor
// * It is only visible (on the type level) to users in the return type of
//   `Url::query_pairs_mut` which is `Serializer<UrlQuery>`
// * `Serializer` keeps its target in a private field
// * Unlike in other `Target` impls, `UrlQuery::finished` does not return `Self`.
impl<'a> Target for ::UrlQuery<'a> {
    fn as_mut_string(&mut self) -> &mut String { &mut self.url.serialization }
    fn finish(self) -> &'a mut ::Url { self.url }
    type Finished = &'a mut ::Url;
}

impl<T: Target> Serializer<T> {
    /// Create a new `application/x-www-form-urlencoded` serializer for the given target.
    ///
    /// If the target is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn new(target: T) -> Self {
        Self::for_suffix(target, 0)
    }

    /// Create a new `application/x-www-form-urlencoded` serializer
    /// for a suffix of the given target.
    ///
    /// If that suffix is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn for_suffix(mut target: T, start_position: usize) -> Self {
        &target.as_mut_string()[start_position..];  // Panic if out of bounds
        Serializer {
            target: Some(target),
            start_position: start_position,
            encoding: EncodingOverride::utf8(),
        }
    }

    /// Remove any existing name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn clear(&mut self) -> &mut Self {
        string(&mut self.target).truncate(self.start_position);
        self
    }

    /// Set the character encoding to be used for names and values before percent-encoding.
    #[cfg(feature = "query_encoding")]
    pub fn encoding_override(&mut self, new: Option<::encoding::EncodingRef>) -> &mut Self {
        self.encoding = EncodingOverride::from_opt_encoding(new).to_output_encoding();
        self
    }

    /// Serialize and append a name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
        append_pair(string(&mut self.target), self.start_position, self.encoding, name, value);
        self
    }

    /// Serialize and append a number of name/value pairs.
    ///
    /// This simply calls `append_pair` repeatedly.
    /// This can be more convenient, so the user doesn’t need to introduce a block
    /// to limit the scope of `Serializer`’s borrow of its string.
    ///
    /// Panics if called after `.finish()`.
    pub fn extend_pairs<I, K, V>(&mut self, iter: I) -> &mut Self
    where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
        {
            let string = string(&mut self.target);
            for pair in iter {
                let &(ref k, ref v) = pair.borrow();
                append_pair(string, self.start_position, self.encoding, k.as_ref(), v.as_ref());
            }
        }
        self
    }

    /// Add a name/value pair whose name is `_charset_`
    /// and whose value is the character encoding’s name.
    /// (See the `encoding_override()` method.)
    ///
    /// Panics if called after `.finish()`.
    #[cfg(feature = "query_encoding")]
    pub fn append_charset(&mut self) -> &mut Self {
        {
            let string = string(&mut self.target);
            append_separator_if_needed(string, self.start_position);
            string.push_str("_charset_=");
            string.push_str(self.encoding.name());
        }
        self
    }

    /// If this serializer was constructed with a string, take and return that string.
    ///
    /// ```rust
    /// use url::form_urlencoded;
    /// let encoded: String = form_urlencoded::Serializer::new(String::new())
    ///     .append_pair("foo", "bar & baz")
    ///     .append_pair("saison", "Été+hiver")
    ///     .finish();
    /// assert_eq!(encoded, "foo=bar+%26+baz&saison=%C3%89t%C3%A9%2Bhiver");
    /// ```
    ///
    /// Panics if called more than once.
    pub fn finish(&mut self) -> T::Finished {
        self.target.take().expect("url::form_urlencoded::Serializer double finish").finish()
    }
}

fn append_separator_if_needed(string: &mut String, start_position: usize) {
    if string.len() > start_position {
        string.push('&')
    }
}

fn string<T: Target>(target: &mut Option<T>) -> &mut String {
    target.as_mut().expect("url::form_urlencoded::Serializer finished").as_mut_string()
}

fn append_pair(string: &mut String, start_position: usize, encoding: EncodingOverride,
               name: &str, value: &str) {
    append_separator_if_needed(string, start_position);
    string.extend(byte_serialize(&encoding.encode(name.into())));
    string.push('=');
    string.extend(byte_serialize(&encoding.encode(value.into())));
}
<|endoftext|>


<commit_before>use std::num::Float;
use std::f64::consts::PI;

use sdl2::event::Event;
use sdl2::mouse;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::{Renderer, RenderDrawer};
use sdl2_ttf::Font;

const SOULLESS_GREY: Color = Color::RGB(175, 175, 175);

const PADDLE_COLOR: Color = SOULLESS_GREY;
const PADDLE_WIDTH: i32 = 12;
const PADDLE_HEIGHT: i32 = 64;
const PADDLE_WALL_PADDING: i32 = 10;

const BALL_COLOR: Color = SOULLESS_GREY;
const BALL_BREADTH: i32 = 8;
const BALL_VELOCITY: f64 = 10.0;
const BALL_INITIAL_ANGLE_DEGREES: i32 = 45;
const BALL_START_POSITION: (i32, i32) = (800 / 2 - BALL_BREADTH / 2, 600 / 2 - BALL_BREADTH / 2);

const SCORE_TOP_PADDING: i32 = 10;
const SCORE_COLOR: Color = SOULLESS_GREY;
const SCORE_FONT_SIZE: isize = 64;

pub struct GameController {
    score_font: Font,

    ball_position: (i32, i32),
    ball_angle: f64,

    player_paddle_y: i32,
    opponent_paddle_y: i32,

    player_score: i32,
    opponent_score: i32
}

impl GameController {
    pub fn new() -> GameController {
        let score_font_path = &Path::new("art/alterebro-pixel-font.ttf");
        let score_font = Font::from_file(score_font_path, SCORE_FONT_SIZE).unwrap();

        return GameController{
            score_font: score_font,
            ball_position: BALL_START_POSITION,
            ball_angle: (BALL_INITIAL_ANGLE_DEGREES as f64).to_radians(),
            player_paddle_y: 280,
            opponent_paddle_y: 10,
            player_score: 0,
            opponent_score: 0
        }
    }

    pub fn tick(&mut self, _: &Event, renderer: &Renderer, drawer: &mut RenderDrawer) {
        self.move_player_paddle();
        self.move_opponent_paddle();
        self.move_ball();
        self.draw_scores(&renderer, drawer);
        self.draw_player(drawer);
        self.draw_opponent(drawer);
        self.draw_ball(drawer);
    }

    fn move_player_paddle(&mut self) {
        let (_, _, y) = mouse::get_mouse_state();
        self.player_paddle_y = y;
    }

    fn move_opponent_paddle(&mut self) {
        let (_, y) = self.ball_position;
        self.opponent_paddle_y = y - PADDLE_HEIGHT / 2;
    }

    // TODO this shouldn't be framerate/vsync dependent.
    // Thanks StackOverflow!
    // http://stackoverflow.com/questions/5830791/find-radians-reflection-angle
    fn move_ball(&mut self) {
        let x_change = (self.ball_angle.cos() * BALL_VELOCITY) as i32;
        let y_change = (self.ball_angle.sin() * BALL_VELOCITY) as i32;

        let (mut x, mut y) = self.ball_position;
        x += x_change;
        y += y_change;

        // Wall collision
        let upper_y_limit = 600 - BALL_BREADTH;
        if y > upper_y_limit || y < 0 { self.ball_angle *= -1.0 }
        if y > upper_y_limit { y = upper_y_limit; }
        else if y < 0 { y = 0; }

        // Paddle collision
        // TODO ball dimensions aren't respected. Left side of ball hits on the left, right side of
        // ball hits on the right. Also need to reset ball x on impact.
        // TODO There's also a bug there the ball can be BALL_BREADTH height above the paddle but
        // still count as a miss. Any part of the ball on the paddle should probably be a save.
        let player_paddle_x = PADDLE_WALL_PADDING + PADDLE_WIDTH;
        let player_paddle_impacted = x <= player_paddle_x && y >= self.player_paddle_y && y <= self.player_paddle_y + PADDLE_HEIGHT;
        let opponent_paddle_x = 800 - PADDLE_WALL_PADDING - PADDLE_WIDTH - BALL_BREADTH;
        let opponent_paddle_impacted = x >= opponent_paddle_x && y >= self.opponent_paddle_y && y <= self.opponent_paddle_y + PADDLE_HEIGHT;

        // Reflect and tweak ball position.
        if player_paddle_impacted || opponent_paddle_impacted {
            self.ball_angle = 0.0 - PI - self.ball_angle;
        }
        if player_paddle_impacted { x = player_paddle_x; }
        else if opponent_paddle_impacted { x = opponent_paddle_x; }

        if x < player_paddle_x || x > opponent_paddle_x {
            if x < player_paddle_x { self.opponent_score += 1; }
            else if x > opponent_paddle_x { self.player_score += 1; }

            self.ball_position = BALL_START_POSITION;
            self.ball_angle = 45.0.to_radians();
        } else {
            self.ball_position = (x, y);
        }
    }

    fn draw_scores(&self, r: &Renderer, d: &mut RenderDrawer) {
        let third = 800 / 3;
        self.draw_score(r, d, self.opponent_score, third);
        self.draw_score(r, d, self.player_score, third * 2);
    }

    fn draw_score(&self, r: &Renderer, d: &mut RenderDrawer, score: i32, x: i32) {
        let surface = self.score_font.render_str_blended(&score.to_string(), SCORE_COLOR).unwrap();
        let t = r.create_texture_from_surface(&surface).unwrap();
        let q = t.query();
        let b = Rect::new(x - q.width / 2, SCORE_TOP_PADDING, q.width, q.height);
        d.copy(&t, None, Some(b));
    }

    fn draw_player(&self, d: &mut RenderDrawer) {
        self.draw_box(d, PADDLE_WALL_PADDING, self.player_paddle_y);
    }

    fn draw_opponent(&self, d: &mut RenderDrawer) {
        self.draw_box(d, 800 - PADDLE_WIDTH - PADDLE_WALL_PADDING, self.opponent_paddle_y);
    }

    fn draw_box(&self, d: &mut RenderDrawer, x: i32, y: i32) {
        d.set_draw_color(PADDLE_COLOR);
        let r = Rect::new(x, y, PADDLE_WIDTH, PADDLE_HEIGHT);
        d.fill_rect(r);
     }

    fn draw_ball(&self, d: &mut RenderDrawer) {
        d.set_draw_color(BALL_COLOR);
        let (x, y) = self.ball_position;
        let r = Rect::new(x, y, BALL_BREADTH, BALL_BREADTH);
        d.fill_rect(r);
    }
}
<commit_msg>Fix paddle being allowed partially offscreen.<commit_after>use std::num::Float;
use std::f64::consts::PI;

use sdl2::event::Event;
use sdl2::mouse;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::{Renderer, RenderDrawer};
use sdl2_ttf::Font;

const SOULLESS_GREY: Color = Color::RGB(175, 175, 175);

const PADDLE_COLOR: Color = SOULLESS_GREY;
const PADDLE_WIDTH: i32 = 12;
const PADDLE_HEIGHT: i32 = 64;
const PADDLE_WALL_PADDING: i32 = 10;

const BALL_COLOR: Color = SOULLESS_GREY;
const BALL_BREADTH: i32 = 8;
const BALL_VELOCITY: f64 = 10.0;
const BALL_INITIAL_ANGLE_DEGREES: i32 = 45;
const BALL_START_POSITION: (i32, i32) = (800 / 2 - BALL_BREADTH / 2, 600 / 2 - BALL_BREADTH / 2);

const SCORE_TOP_PADDING: i32 = 10;
const SCORE_COLOR: Color = SOULLESS_GREY;
const SCORE_FONT_SIZE: isize = 64;

pub struct GameController {
    score_font: Font,

    ball_position: (i32, i32),
    ball_angle: f64,

    player_paddle_y: i32,
    opponent_paddle_y: i32,

    player_score: i32,
    opponent_score: i32
}

impl GameController {
    pub fn new() -> GameController {
        let score_font_path = &Path::new("art/alterebro-pixel-font.ttf");
        let score_font = Font::from_file(score_font_path, SCORE_FONT_SIZE).unwrap();

        return GameController{
            score_font: score_font,
            ball_position: BALL_START_POSITION,
            ball_angle: (BALL_INITIAL_ANGLE_DEGREES as f64).to_radians(),
            player_paddle_y: 280,
            opponent_paddle_y: 10,
            player_score: 0,
            opponent_score: 0
        }
    }

    pub fn tick(&mut self, _: &Event, renderer: &Renderer, drawer: &mut RenderDrawer) {
        self.move_player_paddle();
        self.move_opponent_paddle();
        self.move_ball();
        self.draw_scores(&renderer, drawer);
        self.draw_player(drawer);
        self.draw_opponent(drawer);
        self.draw_ball(drawer);
    }

    fn move_player_paddle(&mut self) {
        let (_, _, mut y) = mouse::get_mouse_state();
        if y < 0 { y = 0; }
        else if y + PADDLE_HEIGHT > 600 { y = 600 - PADDLE_HEIGHT; }

        self.player_paddle_y = y;
    }

    fn move_opponent_paddle(&mut self) {
        let (_, y) = self.ball_position;
        self.opponent_paddle_y = y - PADDLE_HEIGHT / 2;
    }

    // TODO this shouldn't be framerate/vsync dependent.
    // Thanks StackOverflow!
    // http://stackoverflow.com/questions/5830791/find-radians-reflection-angle
    fn move_ball(&mut self) {
        let x_change = (self.ball_angle.cos() * BALL_VELOCITY) as i32;
        let y_change = (self.ball_angle.sin() * BALL_VELOCITY) as i32;

        let (mut x, mut y) = self.ball_position;
        x += x_change;
        y += y_change;

        // Wall collision
        let upper_y_limit = 600 - BALL_BREADTH;
        if y > upper_y_limit || y < 0 { self.ball_angle *= -1.0 }
        if y > upper_y_limit { y = upper_y_limit; }
        else if y < 0 { y = 0; }

        // Paddle collision
        // TODO ball dimensions aren't respected. Left side of ball hits on the left, right side of
        // ball hits on the right. Also need to reset ball x on impact.
        // TODO There's also a bug there the ball can be BALL_BREADTH height above the paddle but
        // still count as a miss. Any part of the ball on the paddle should probably be a save.
        let player_paddle_x = PADDLE_WALL_PADDING + PADDLE_WIDTH;
        let player_paddle_impacted = x <= player_paddle_x && y >= self.player_paddle_y && y <= self.player_paddle_y + PADDLE_HEIGHT;
        let opponent_paddle_x = 800 - PADDLE_WALL_PADDING - PADDLE_WIDTH - BALL_BREADTH;
        let opponent_paddle_impacted = x >= opponent_paddle_x && y >= self.opponent_paddle_y && y <= self.opponent_paddle_y + PADDLE_HEIGHT;

        // Reflect and tweak ball position.
        if player_paddle_impacted || opponent_paddle_impacted {
            self.ball_angle = 0.0 - PI - self.ball_angle;
        }
        if player_paddle_impacted { x = player_paddle_x; }
        else if opponent_paddle_impacted { x = opponent_paddle_x; }

        if x < player_paddle_x || x > opponent_paddle_x {
            if x < player_paddle_x { self.opponent_score += 1; }
            else if x > opponent_paddle_x { self.player_score += 1; }

            self.ball_position = BALL_START_POSITION;
            self.ball_angle = 45.0.to_radians();
        } else {
            self.ball_position = (x, y);
        }
    }

    fn draw_scores(&self, r: &Renderer, d: &mut RenderDrawer) {
        let third = 800 / 3;
        self.draw_score(r, d, self.opponent_score, third);
        self.draw_score(r, d, self.player_score, third * 2);
    }

    fn draw_score(&self, r: &Renderer, d: &mut RenderDrawer, score: i32, x: i32) {
        let surface = self.score_font.render_str_blended(&score.to_string(), SCORE_COLOR).unwrap();
        let t = r.create_texture_from_surface(&surface).unwrap();
        let q = t.query();
        let b = Rect::new(x - q.width / 2, SCORE_TOP_PADDING, q.width, q.height);
        d.copy(&t, None, Some(b));
    }

    fn draw_player(&self, d: &mut RenderDrawer) {
        self.draw_box(d, PADDLE_WALL_PADDING, self.player_paddle_y);
    }

    fn draw_opponent(&self, d: &mut RenderDrawer) {
        self.draw_box(d, 800 - PADDLE_WIDTH - PADDLE_WALL_PADDING, self.opponent_paddle_y);
    }

    fn draw_box(&self, d: &mut RenderDrawer, x: i32, y: i32) {
        d.set_draw_color(PADDLE_COLOR);
        let r = Rect::new(x, y, PADDLE_WIDTH, PADDLE_HEIGHT);
        d.fill_rect(r);
     }

    fn draw_ball(&self, d: &mut RenderDrawer) {
        d.set_draw_color(BALL_COLOR);
        let (x, y) = self.ball_position;
        let r = Rect::new(x, y, BALL_BREADTH, BALL_BREADTH);
        d.fill_rect(r);
    }
}
<|endoftext|>


<commit_before>
pub trait GameDescriptor {
	fn survival(&self) -> &[u8];
	fn birth(&self) -> &[u8];
	fn live_cells(&self) -> &[Coord];
}

#[derive(Debug, PartialEq)]
pub struct Coord {
	pub x: u8,
	pub y: u8,
}

pub struct DefaultGameDescriptor {
	survival: Vec<u8>,
	birth: Vec<u8>,
	live_cells: Vec<Coord>,
}

impl DefaultGameDescriptor {
	pub fn new() -> Self {
		DefaultGameDescriptor {
			survival: vec![],
			birth: vec![],
			live_cells: vec![],
		}
	}

	pub fn add_survival(&mut self, value: u8) {
		self.survival.push(value);
	}

	pub fn add_birth(&mut self, value: u8) {
		self.birth.push(value);
	}

	pub fn add_live_cell(&mut self, x: u8, y: u8) {
		self.live_cells.push(Coord{ x: x, y: y });
	}
}

impl GameDescriptor for DefaultGameDescriptor {
	fn survival(&self) -> &[u8] {
		&self.survival
	}

	fn birth(&self) -> &[u8] {
		&self.birth
	}

	fn live_cells(&self) -> &[Coord] {
		&self.live_cells
	}
}
<commit_msg>changed coord types from u8 to i16<commit_after>
pub trait GameDescriptor {
	fn survival(&self) -> &[u8];
	fn birth(&self) -> &[u8];
	fn live_cells(&self) -> &[Coord];
}

#[derive(Debug, PartialEq)]
pub struct Coord {
	pub x: i16,
	pub y: i16,
}

pub struct DefaultGameDescriptor {
	survival: Vec<u8>,
	birth: Vec<u8>,
	live_cells: Vec<Coord>,
}

impl DefaultGameDescriptor {
	pub fn new() -> Self {
		DefaultGameDescriptor {
			survival: vec![],
			birth: vec![],
			live_cells: vec![],
		}
	}

	pub fn add_survival(&mut self, value: u8) {
		self.survival.push(value);
	}

	pub fn add_birth(&mut self, value: u8) {
		self.birth.push(value);
	}

	pub fn add_live_cell(&mut self, x: i16, y: i16) {
		self.live_cells.push(Coord{ x: x, y: y });
	}
}

impl GameDescriptor for DefaultGameDescriptor {
	fn survival(&self) -> &[u8] {
		&self.survival
	}

	fn birth(&self) -> &[u8] {
		&self.birth
	}

	fn live_cells(&self) -> &[Coord] {
		&self.live_cells
	}
}
<|endoftext|>


<commit_before>use super::Span;
use super::dimensions::{self, Dimension, Partitioned};
use rand::ThreadRng;
use std::ops::Add;
use std::iter::FromIterator;
use std::slice::Iter as SliceIter;
use std::collections::HashMap;
use std::collections::hash_map::Iter as HashMapIter;

/// Trait for defining geometric spaces.
pub trait Space {
    /// The data representation of the space.
    type Repr: Clone;

    /// Generate a random sample from the space.
    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr;

    /// Return the number of dimensions in the space.
    fn dim(&self) -> usize;

    /// Return the number of linear combinations of values in the space.
    fn span(&self) -> Span;
}

/// Geometric space for agent actions.
///
/// Currently the only supported representation for actions. In future we will need to handle
/// continuous actions.
pub type ActionSpace = UnitarySpace<dimensions::Discrete>;

/// An empty space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct EmptySpace;

impl Space for EmptySpace {
    type Repr = ();

    fn sample(&self, _: &mut ThreadRng) -> Self::Repr {
        ()
    }

    fn dim(&self) -> usize {
        0
    }

    fn span(&self) -> Span {
        Span::Null
    }
}

/// 1-dimensional space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct UnitarySpace<D: Dimension>(D);

impl<D: Dimension> UnitarySpace<D> {
    pub fn new(d: D) -> Self {
        UnitarySpace(d)
    }
}

impl UnitarySpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> UnitarySpace<Partitioned> {
        UnitarySpace(Partitioned::from_continuous(self.0, density))
    }
}

impl<D: Dimension> Space for UnitarySpace<D> {
    type Repr = D::Value;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.0.sample(rng)
    }

    fn dim(&self) -> usize {
        1
    }

    fn span(&self) -> Span {
        self.0.span()
    }
}

/// 2-dimensional homogeneous space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct PairSpace<D1, D2>((D1, D2))
    where D1: Dimension,
          D2: Dimension;

impl<D1: Dimension, D2: Dimension> PairSpace<D1, D2> {
    pub fn new(d1: D1, d2: D2) -> Self {
        PairSpace((d1, d2))
    }
}

impl PairSpace<dimensions::Continuous, dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> PairSpace<Partitioned, Partitioned> {
        PairSpace((Partitioned::from_continuous((self.0).0, density),
                   Partitioned::from_continuous((self.0).1, density)))
    }
}

impl<D1: Dimension, D2: Dimension> Space for PairSpace<D1, D2> {
    type Repr = (D1::Value, D2::Value);

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        ((self.0).0.sample(rng), (self.0).1.sample(rng))
    }

    fn dim(&self) -> usize {
        2
    }

    fn span(&self) -> Span {
        (self.0).0.span()*(self.0).1.span()
    }
}

/// N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct RegularSpace<D: Dimension> {
    dimensions: Vec<D>,
    span: Span,
}

impl<D: Dimension> RegularSpace<D> {
    pub fn new(dimensions: Vec<D>) -> Self {
        let mut s = Self::empty();

        for d in dimensions {
            s = s.push(d);
        }

        s
    }

    pub fn empty() -> Self {
        RegularSpace {
            dimensions: vec![],
            span: Span::Null,
        }
    }

    pub fn push(mut self, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.push(d);

        self
    }

    pub fn iter(&self) -> SliceIter<D> {
        self.dimensions.iter()
    }
}

impl RegularSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> RegularSpace<Partitioned> {
        self.into_iter()
            .map(|d| Partitioned::from_continuous(d, density))
            .collect()
    }
}

impl RegularSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .iter()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for RegularSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|d| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<D> for RegularSpace<D> {
    fn from_iter<I: IntoIterator<Item = D>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for RegularSpace<D> {
    type Item = D;
    type IntoIter = ::std::vec::IntoIter<D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<D> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: D) -> Self::Output {
        self.push(rhs)
    }
}

impl<D: Dimension> Add<RegularSpace<D>> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: RegularSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

/// Named, N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct NamedSpace<D: Dimension> {
    dimensions: HashMap<String, D>,
    span: Span,
}

impl<D: Dimension> NamedSpace<D> {
    pub fn new<S: Into<String>>(dimensions: Vec<(S, D)>) -> Self {
        let mut s = Self::empty();

        for (name, d) in dimensions {
            s = s.push(name, d);
        }

        s
    }

    pub fn empty() -> Self {
        NamedSpace {
            dimensions: HashMap::new(),
            span: Span::Null,
        }
    }

    pub fn push<S: Into<String>>(mut self, name: S, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.insert(name.into(), d);

        self
    }

    pub fn iter(&self) -> HashMapIter<String, D> {
        self.dimensions.iter()
    }
}

impl NamedSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> NamedSpace<Partitioned> {
        self.into_iter()
            .map(|(name, d)| (name, Partitioned::from_continuous(d, density)))
            .collect()
    }
}

impl NamedSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .values()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for NamedSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|(_, d)| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<(String, D)> for NamedSpace<D> {
    fn from_iter<I: IntoIterator<Item = (String, D)>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for NamedSpace<D> {
    type Item = (String, D);
    type IntoIter = ::std::collections::hash_map::IntoIter<String, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<NamedSpace<D>> for NamedSpace<D> {
    type Output = Self;

    fn add(self, rhs: NamedSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

#[cfg(test)]
mod tests {
    use super::{Space, EmptySpace, UnitarySpace, PairSpace, RegularSpace};
    use geometry::Span;
    use geometry::dimensions::*;
    use ndarray::arr1;
    use rand::thread_rng;

    #[test]
    fn test_null_space() {
        let ns = EmptySpace;
        let mut rng = thread_rng();

        assert_eq!(ns.sample(&mut rng), ());
        assert_eq!(ns.dim(), 0);
        assert_eq!(ns.span(), Span::Null);
    }

    #[test]
    fn test_unitary_space() {
        let us = UnitarySpace::new(Discrete::new(2));
        let mut rng = thread_rng();

        let mut counts = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = us.sample(&mut rng);
            counts[sample] += 1.0;

            assert!(sample == 0 || sample == 1);
        }

        assert!((counts/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert_eq!(us.dim(), 1);
        assert_eq!(us.span(), Span::Finite(2));
    }

    #[test]
    fn test_pair_space() {
        let ps = PairSpace::new(Discrete::new(2), Discrete::new(2));

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = ps.sample(&mut rng);

            c1[sample.0] += 1.0;
            c2[sample.1] += 1.0;

            assert!(sample.0 == 0 || sample.0 == 1);
            assert!(sample.1 == 0 || sample.1 == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(ps.dim(), 2);
        assert_eq!(ps.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space() {
        let space = RegularSpace::new(vec![Discrete::new(2); 2]);

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = space.sample(&mut rng);

            c1[sample[0]] += 1.0;
            c2[sample[1]] += 1.0;

            assert!(sample[0] == 0 || sample[0] == 1);
            assert!(sample[1] == 0 || sample[1] == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(space.dim(), 2);
        assert_eq!(space.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space_sugar() {
        let mut sa = RegularSpace::new(vec![Discrete::new(2); 2]);
        let mut sb = RegularSpace::empty() + Discrete::new(2) + Discrete::new(2);

        assert_eq!(sa.dim(), sb.dim());
        assert_eq!(sa.span(), sb.span());

        sa += Discrete::new(3);
        sb += Discrete::new(3);

        assert_eq!(sa.dim(), 3);
        assert_eq!(sa.dim(), sb.dim());

        assert_eq!(sa.span(), Span::Finite(4)*Span::Finite(3));
        assert_eq!(sa.span(), sb.span());
    }
}
<commit_msg>tests(geometry): fix tests of deprecated features<commit_after>use super::Span;
use super::dimensions::{self, Dimension, Partitioned};
use rand::ThreadRng;
use std::ops::Add;
use std::iter::FromIterator;
use std::slice::Iter as SliceIter;
use std::collections::HashMap;
use std::collections::hash_map::Iter as HashMapIter;

/// Trait for defining geometric spaces.
pub trait Space {
    /// The data representation of the space.
    type Repr: Clone;

    /// Generate a random sample from the space.
    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr;

    /// Return the number of dimensions in the space.
    fn dim(&self) -> usize;

    /// Return the number of linear combinations of values in the space.
    fn span(&self) -> Span;
}

/// Geometric space for agent actions.
///
/// Currently the only supported representation for actions. In future we will need to handle
/// continuous actions.
pub type ActionSpace = UnitarySpace<dimensions::Discrete>;

/// An empty space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct EmptySpace;

impl Space for EmptySpace {
    type Repr = ();

    fn sample(&self, _: &mut ThreadRng) -> Self::Repr {
        ()
    }

    fn dim(&self) -> usize {
        0
    }

    fn span(&self) -> Span {
        Span::Null
    }
}

/// 1-dimensional space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct UnitarySpace<D: Dimension>(D);

impl<D: Dimension> UnitarySpace<D> {
    pub fn new(d: D) -> Self {
        UnitarySpace(d)
    }
}

impl UnitarySpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> UnitarySpace<Partitioned> {
        UnitarySpace(Partitioned::from_continuous(self.0, density))
    }
}

impl<D: Dimension> Space for UnitarySpace<D> {
    type Repr = D::Value;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.0.sample(rng)
    }

    fn dim(&self) -> usize {
        1
    }

    fn span(&self) -> Span {
        self.0.span()
    }
}

/// 2-dimensional homogeneous space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct PairSpace<D1, D2>((D1, D2))
    where D1: Dimension,
          D2: Dimension;

impl<D1: Dimension, D2: Dimension> PairSpace<D1, D2> {
    pub fn new(d1: D1, d2: D2) -> Self {
        PairSpace((d1, d2))
    }
}

impl PairSpace<dimensions::Continuous, dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> PairSpace<Partitioned, Partitioned> {
        PairSpace((Partitioned::from_continuous((self.0).0, density),
                   Partitioned::from_continuous((self.0).1, density)))
    }
}

impl<D1: Dimension, D2: Dimension> Space for PairSpace<D1, D2> {
    type Repr = (D1::Value, D2::Value);

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        ((self.0).0.sample(rng), (self.0).1.sample(rng))
    }

    fn dim(&self) -> usize {
        2
    }

    fn span(&self) -> Span {
        (self.0).0.span()*(self.0).1.span()
    }
}

/// N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct RegularSpace<D: Dimension> {
    dimensions: Vec<D>,
    span: Span,
}

impl<D: Dimension> RegularSpace<D> {
    pub fn new(dimensions: Vec<D>) -> Self {
        let mut s = Self::empty();

        for d in dimensions {
            s = s.push(d);
        }

        s
    }

    pub fn empty() -> Self {
        RegularSpace {
            dimensions: vec![],
            span: Span::Null,
        }
    }

    pub fn push(mut self, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.push(d);

        self
    }

    pub fn iter(&self) -> SliceIter<D> {
        self.dimensions.iter()
    }
}

impl RegularSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> RegularSpace<Partitioned> {
        self.into_iter()
            .map(|d| Partitioned::from_continuous(d, density))
            .collect()
    }
}

impl RegularSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .iter()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for RegularSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|d| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<D> for RegularSpace<D> {
    fn from_iter<I: IntoIterator<Item = D>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for RegularSpace<D> {
    type Item = D;
    type IntoIter = ::std::vec::IntoIter<D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<D> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: D) -> Self::Output {
        self.push(rhs)
    }
}

impl<D: Dimension> Add<RegularSpace<D>> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: RegularSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

/// Named, N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct NamedSpace<D: Dimension> {
    dimensions: HashMap<String, D>,
    span: Span,
}

impl<D: Dimension> NamedSpace<D> {
    pub fn new<S: Into<String>>(dimensions: Vec<(S, D)>) -> Self {
        let mut s = Self::empty();

        for (name, d) in dimensions {
            s = s.push(name, d);
        }

        s
    }

    pub fn empty() -> Self {
        NamedSpace {
            dimensions: HashMap::new(),
            span: Span::Null,
        }
    }

    pub fn push<S: Into<String>>(mut self, name: S, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.insert(name.into(), d);

        self
    }

    pub fn iter(&self) -> HashMapIter<String, D> {
        self.dimensions.iter()
    }
}

impl NamedSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> NamedSpace<Partitioned> {
        self.into_iter()
            .map(|(name, d)| (name, Partitioned::from_continuous(d, density)))
            .collect()
    }
}

impl NamedSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .values()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for NamedSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|(_, d)| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<(String, D)> for NamedSpace<D> {
    fn from_iter<I: IntoIterator<Item = (String, D)>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for NamedSpace<D> {
    type Item = (String, D);
    type IntoIter = ::std::collections::hash_map::IntoIter<String, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<NamedSpace<D>> for NamedSpace<D> {
    type Output = Self;

    fn add(self, rhs: NamedSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

#[cfg(test)]
mod tests {
    use super::{Space, EmptySpace, UnitarySpace, PairSpace, RegularSpace};
    use geometry::Span;
    use geometry::dimensions::*;
    use ndarray::arr1;
    use rand::thread_rng;

    #[test]
    fn test_null_space() {
        let ns = EmptySpace;
        let mut rng = thread_rng();

        assert_eq!(ns.sample(&mut rng), ());
        assert_eq!(ns.dim(), 0);
        assert_eq!(ns.span(), Span::Null);
    }

    #[test]
    fn test_unitary_space() {
        let us = UnitarySpace::new(Discrete::new(2));
        let mut rng = thread_rng();

        let mut counts = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = us.sample(&mut rng);
            counts[sample] += 1.0;

            assert!(sample == 0 || sample == 1);
        }

        assert!((counts/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert_eq!(us.dim(), 1);
        assert_eq!(us.span(), Span::Finite(2));
    }

    #[test]
    fn test_pair_space() {
        let ps = PairSpace::new(Discrete::new(2), Discrete::new(2));

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = ps.sample(&mut rng);

            c1[sample.0] += 1.0;
            c2[sample.1] += 1.0;

            assert!(sample.0 == 0 || sample.0 == 1);
            assert!(sample.1 == 0 || sample.1 == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(ps.dim(), 2);
        assert_eq!(ps.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space() {
        let space = RegularSpace::new(vec![Discrete::new(2); 2]);

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = space.sample(&mut rng);

            c1[sample[0]] += 1.0;
            c2[sample[1]] += 1.0;

            assert!(sample[0] == 0 || sample[0] == 1);
            assert!(sample[1] == 0 || sample[1] == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(space.dim(), 2);
        assert_eq!(space.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space_sugar() {
        let mut sa = RegularSpace::new(vec![Discrete::new(2); 2]);
        let mut sb = RegularSpace::empty() + Discrete::new(2) + Discrete::new(2);

        assert_eq!(sa.dim(), sb.dim());
        assert_eq!(sa.span(), sb.span());

        sa = sa + Discrete::new(3);
        sb = sb + Discrete::new(3);

        assert_eq!(sa.dim(), 3);
        assert_eq!(sa.dim(), sb.dim());

        assert_eq!(sa.span(), Span::Finite(4)*Span::Finite(3));
        assert_eq!(sa.span(), sb.span());
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Hough_transform
//
// Contributed by Gavin Baker <gavinb@antonym.org>
// Adapted from the Go version

use std::io::{BufferedReader, BufferedWriter, File};

// Simple 8-bit grayscale image

struct ImageGray8 {
    width: uint,
    height: uint,
    data: Vec<u8>,
}

fn load_pgm(filename: &str) -> ImageGray8 {

    // Open file

    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    // Read header

    let magic_in = file.read_line().unwrap();
    let width_in = file.read_line().unwrap();
    let height_in = file.read_line().unwrap();
    let maxval_in = file.read_line().unwrap();

    assert!(magic_in.as_slice() == "P5\n");
    assert!(maxval_in.as_slice() == "255\n");

    // Parse header

    let width: uint = from_str(width_in.as_slice().trim()).unwrap();
    let height: uint = from_str(height_in.as_slice().trim()).unwrap();

    println!("Reading pgm file {}: {} x {}", filename, width, height);

    // Create image and allocate buffer

    let mut img = ImageGray8 {
        width: width,
        height: height,
        data: Vec::from_elem(width*height, 0),
    };

    // Read image data

    match file.read_at_least(img.data.len(), img.data.as_mut_slice()) {
        Ok(bytes_read) => println!("Read {} bytes", bytes_read),
        Err(e) => println!("error reading: {}", e)
    }

    img
}

fn save_pgm(img: &ImageGray8, filename: &str) {

    // Open file

    let path = Path::new(filename);
    let mut file = BufferedWriter::new(File::create(&path));

    // Write header

    match file.write_line(format!("P5\n{}\n{}\n255", img.width, img.height).as_slice()) {
        Err(e) => println!("Failed to write header: {}", e),
        _ => {},
    }

    println!("Writing pgm file {}: {} x {}", filename, img.width, img.height);

    // Write binary image data

    match file.write(img.data.as_slice()) {
        Err(e) => println!("Failed to image data: {}", e),
        _ => {},
    }
}

fn hough(image: &ImageGray8, out_width: uint, out_height: uint) -> ImageGray8 {

    let in_width = image.width;
    let in_height = image.height;

    // Allocate accumulation buffer

    let out_height = ((out_height/2) * 2) as uint;
    let mut accum = ImageGray8 {
        width: out_width,
        height: out_height,
        data: Vec::from_elem(out_width*out_height, 255),
    };

    // Transform extents

    let rmax = (in_width as f64).hypot(in_height as f64);
    let dr = rmax / (out_height/2) as f64;
    let dth = std::f64::consts::PI / out_width as f64;

    // Process input image in raster order

    for y in range(0, in_height) {
        for x in range(0, in_width) {
            let in_idx = y*in_width+x;
            let col = image.data[in_idx];
            if col == 255 {
                continue;
            }

            // Project into rho,theta space

            for jtx in range(0, out_width) {
                let th = dth * (jtx as f64);
                let r = (x as f64)*(th.cos()) + (y as f64)*(th.sin());

                let iry = out_height/2 - (r/(dr as f64)+0.5).floor() as uint;
                let out_idx = jtx + iry * out_width;
                let col = accum.data[out_idx];
                if col > 0 {
                    *accum.data.get_mut(out_idx) = col - 1;
                }
            }
        }
    }
    accum
}

fn main() {

    let image = load_pgm("../src/resources/Pentagon.pgm");

    let accum = hough(&image, 460, 360);

    save_pgm(&accum, "hough.pgm");
}
<commit_msg>Hough transform: fix warnings<commit_after>// Implements http://rosettacode.org/wiki/Hough_transform
//
// Contributed by Gavin Baker <gavinb@antonym.org>
// Adapted from the Go version

#![allow(dead_code)]

use std::io::{BufferedReader, BufferedWriter, File};

// Simple 8-bit grayscale image

struct ImageGray8 {
    width: uint,
    height: uint,
    data: Vec<u8>,
}

fn load_pgm(filename: &str) -> ImageGray8 {

    // Open file

    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    // Read header

    let magic_in = file.read_line().unwrap();
    let width_in = file.read_line().unwrap();
    let height_in = file.read_line().unwrap();
    let maxval_in = file.read_line().unwrap();

    assert!(magic_in.as_slice() == "P5\n");
    assert!(maxval_in.as_slice() == "255\n");

    // Parse header

    let width: uint = from_str(width_in.as_slice().trim()).unwrap();
    let height: uint = from_str(height_in.as_slice().trim()).unwrap();

    println!("Reading pgm file {}: {} x {}", filename, width, height);

    // Create image and allocate buffer

    let mut img = ImageGray8 {
        width: width,
        height: height,
        data: Vec::from_elem(width*height, 0),
    };

    // Read image data

    match file.read_at_least(img.data.len(), img.data.as_mut_slice()) {
        Ok(bytes_read) => println!("Read {} bytes", bytes_read),
        Err(e) => println!("error reading: {}", e)
    }

    img
}

fn save_pgm(img: &ImageGray8, filename: &str) {

    // Open file

    let path = Path::new(filename);
    let mut file = BufferedWriter::new(File::create(&path));

    // Write header

    match file.write_line(format!("P5\n{}\n{}\n255", img.width, img.height).as_slice()) {
        Err(e) => println!("Failed to write header: {}", e),
        _ => {},
    }

    println!("Writing pgm file {}: {} x {}", filename, img.width, img.height);

    // Write binary image data

    match file.write(img.data.as_slice()) {
        Err(e) => println!("Failed to image data: {}", e),
        _ => {},
    }
}

fn hough(image: &ImageGray8, out_width: uint, out_height: uint) -> ImageGray8 {

    let in_width = image.width;
    let in_height = image.height;

    // Allocate accumulation buffer

    let out_height = ((out_height/2) * 2) as uint;
    let mut accum = ImageGray8 {
        width: out_width,
        height: out_height,
        data: Vec::from_elem(out_width*out_height, 255),
    };

    // Transform extents

    let rmax = (in_width as f64).hypot(in_height as f64);
    let dr = rmax / (out_height/2) as f64;
    let dth = std::f64::consts::PI / out_width as f64;

    // Process input image in raster order

    for y in range(0, in_height) {
        for x in range(0, in_width) {
            let in_idx = y*in_width+x;
            let col = image.data[in_idx];
            if col == 255 {
                continue;
            }

            // Project into rho,theta space

            for jtx in range(0, out_width) {
                let th = dth * (jtx as f64);
                let r = (x as f64)*(th.cos()) + (y as f64)*(th.sin());

                let iry = out_height/2 - (r/(dr as f64)+0.5).floor() as uint;
                let out_idx = jtx + iry * out_width;
                let col = accum.data[out_idx];
                if col > 0 {
                    *accum.data.get_mut(out_idx) = col - 1;
                }
            }
        }
    }
    accum
}

#[cfg(not(test))]
fn main() {

    let image = load_pgm("../src/resources/Pentagon.pgm");

    let accum = hough(&image, 460, 360);

    save_pgm(&accum, "hough.pgm");
}
<|endoftext|>


<commit_before>use decoders::Image;
use imageops::OpBuffer;
use std::cmp;

pub fn base(_: &Image, buf: &mut OpBuffer) {
  let xs = [0.0, 0.30, 0.5, 0.70, 1.0];
  let ys = [0.0, 0.25, 0.5, 0.75, 1.0];
  let func = SplineFunc::new(&xs, &ys);

  for pix in buf.data.chunks_mut(3) {
    pix[0] = func.interpolate(pix[0]);
    pix[1] = pix[1];
    pix[2] = pix[2];
  }
}

struct SplineFunc<'a> {
  xs: &'a [f32],
  ys: &'a [f32],
  c1s: Vec<f32>,
  c2s: Vec<f32>,
  c3s: Vec<f32>,
}

impl<'a> SplineFunc<'a> {
  // Monotone cubic interpolation code adapted from the Javascript example in Wikipedia
  fn new(xs: &'a[f32], ys: &'a[f32]) -> SplineFunc<'a> {
    if xs.len() != ys.len() { panic!("Different number of Xs and Ys for Spline"); }
    if xs.len() < 2 { panic!("Need at least 2 points for Spline"); }

	  // Get consecutive differences and slopes
    let mut dxs = Vec::new();
    let mut dys = Vec::new();
    let mut slopes = Vec::new();
    for i in 0..(xs.len()-1) {
      let dx = xs[i+1] - xs[i];
      let dy = ys[i+1] - ys[i];
      dxs.push(dx);
      dys.push(dy);
      slopes.push(dy/dx);
    }

	  // Get degree-1 coefficients
    let mut c1s = vec![slopes[0]];
    for i in 0..(dxs.len()-1) {
      let m = slopes[i];
      let next = slopes[i+1];
      if m*next <= 0.0 {
        c1s.push(0.0);
      } else {
        let dx = dxs[i];
        let dxnext = dxs[i+1];
        let common = dx + dxnext;
        c1s.push(3.0*common/((common+dxnext)/m + (common + dx)/next));
      }
    }
    c1s.push(slopes[slopes.len()-1]);

	  // Get degree-2 and degree-3 coefficients
    let mut c2s = Vec::new();
    let mut c3s = Vec::new();
    for i in 0..(c1s.len()-1) {
      let c1 = c1s[i];
      let slope = slopes[i];
      let invdx = 1.0 / dxs[i];
      let common = c1+c1s[i+1] - slope - slope;
      c2s.push((slope-c1-common)*invdx);
      c3s.push(common*invdx*invdx);
    }

    SplineFunc {
      xs: xs,
      ys: ys,
        c1s: c1s,
      c2s: c2s,
      c3s: c3s,
    }
  }

  fn interpolate(&self, val: f32) -> f32 {
		// Anything at or beyond the last value returns the last value
    let end = self.xs[self.xs.len()-1];
    if val >= end {
      return self.ys[self.ys.len()-1];
    }

		// Search for the interval x is in, returning the corresponding y if x is one of the original xs
    let mut low: isize = 0;
    let mut mid: isize;
    let mut high: isize = (self.c3s.len() - 1) as isize;

		while low <= high {
      mid = (low+high)/2;
      let xhere = self.xs[mid as usize];
      if xhere < val { low = mid + 1; }
      else if xhere > val { high = mid - 1; }
      else { return self.ys[mid as usize] }
		}
    let i = cmp::max(0, high) as usize;

		// Interpolate
    let diff = val - self.xs[i];

    self.ys[i] + self.c1s[i]*diff + self.c2s[i]*diff*diff + self.c3s[i]*diff*diff*diff
	}
}
<commit_msg>curves: use threads to speedup<commit_after>use decoders::Image;
use imageops::OpBuffer;
use std::cmp;

pub fn base(_: &Image, buf: &mut OpBuffer) {
  let xs = [0.0, 0.30, 0.5, 0.70, 1.0];
  let ys = [0.0, 0.25, 0.5, 0.75, 1.0];
  let func = SplineFunc::new(&xs, &ys);

  buf.mutate_lines(&(|line: &mut [f32], _| {
    for pix in line.chunks_mut(3) {
      pix[0] = func.interpolate(pix[0]);
      pix[1] = pix[1];
      pix[2] = pix[2];
    }
  }));
}

struct SplineFunc<'a> {
  xs: &'a [f32],
  ys: &'a [f32],
  c1s: Vec<f32>,
  c2s: Vec<f32>,
  c3s: Vec<f32>,
}

impl<'a> SplineFunc<'a> {
  // Monotone cubic interpolation code adapted from the Javascript example in Wikipedia
  fn new(xs: &'a[f32], ys: &'a[f32]) -> SplineFunc<'a> {
    if xs.len() != ys.len() { panic!("Different number of Xs and Ys for Spline"); }
    if xs.len() < 2 { panic!("Need at least 2 points for Spline"); }

	  // Get consecutive differences and slopes
    let mut dxs = Vec::new();
    let mut dys = Vec::new();
    let mut slopes = Vec::new();
    for i in 0..(xs.len()-1) {
      let dx = xs[i+1] - xs[i];
      let dy = ys[i+1] - ys[i];
      dxs.push(dx);
      dys.push(dy);
      slopes.push(dy/dx);
    }

	  // Get degree-1 coefficients
    let mut c1s = vec![slopes[0]];
    for i in 0..(dxs.len()-1) {
      let m = slopes[i];
      let next = slopes[i+1];
      if m*next <= 0.0 {
        c1s.push(0.0);
      } else {
        let dx = dxs[i];
        let dxnext = dxs[i+1];
        let common = dx + dxnext;
        c1s.push(3.0*common/((common+dxnext)/m + (common + dx)/next));
      }
    }
    c1s.push(slopes[slopes.len()-1]);

	  // Get degree-2 and degree-3 coefficients
    let mut c2s = Vec::new();
    let mut c3s = Vec::new();
    for i in 0..(c1s.len()-1) {
      let c1 = c1s[i];
      let slope = slopes[i];
      let invdx = 1.0 / dxs[i];
      let common = c1+c1s[i+1] - slope - slope;
      c2s.push((slope-c1-common)*invdx);
      c3s.push(common*invdx*invdx);
    }

    SplineFunc {
      xs: xs,
      ys: ys,
        c1s: c1s,
      c2s: c2s,
      c3s: c3s,
    }
  }

  fn interpolate(&self, val: f32) -> f32 {
		// Anything at or beyond the last value returns the last value
    let end = self.xs[self.xs.len()-1];
    if val >= end {
      return self.ys[self.ys.len()-1];
    }

		// Search for the interval x is in, returning the corresponding y if x is one of the original xs
    let mut low: isize = 0;
    let mut mid: isize;
    let mut high: isize = (self.c3s.len() - 1) as isize;

		while low <= high {
      mid = (low+high)/2;
      let xhere = self.xs[mid as usize];
      if xhere < val { low = mid + 1; }
      else if xhere > val { high = mid - 1; }
      else { return self.ys[mid as usize] }
		}
    let i = cmp::max(0, high) as usize;

		// Interpolate
    let diff = val - self.xs[i];

    self.ys[i] + self.c1s[i]*diff + self.c2s[i]*diff*diff + self.c3s[i]*diff*diff*diff
	}
}
<|endoftext|>