<commit_before>use hex::*;
use regex::Regex;
use semver::Version;
use std::iter::*;
use std::error::{Error};
use url::{Url};

/* Example lines:

# SHA256 of the file                                             Name       Version Size  [delta/full] release%
e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full
a4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-delta.7z 123 delta
b4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-beta.7z 34567 full 5%
*/

#[derive(Debug)]
pub struct ReleaseEntry {
  pub sha256: [u8; 32],
  pub filename_or_url: String,
  pub version: Version,
  pub length: i64,
  pub is_delta: bool,
  pub percentage: i32,
}

impl Default for ReleaseEntry {
  fn default() -> ReleaseEntry {
    ReleaseEntry {
      filename_or_url: "Foobdar".to_owned(),
      version: Version::parse("1.0.0").unwrap(),
      is_delta: true,
      length: 42,
      sha256: [0; 32],
      percentage: 100,
    }
  }
}

lazy_static! {
  static ref SCHEME: Regex = Regex::new(r"^https:").unwrap();
}

lazy_static! {
  static ref COMMENT: Regex = Regex::new(r"#.*$").unwrap();
}

impl ReleaseEntry {
  fn parse_sha256(sha256: &str, to_fill: &mut ReleaseEntry) -> Result<bool, Box<Error>> {
    let ret = try!(sha256.from_hex());
    if ret.len() != 32 {
      return Err(From::from("SHA256 is malformed"));
    }

    for i in 0..32 { to_fill.sha256[i] = ret[i]; }
    return Ok(true);
  }

  fn parse_delta_full(delta_or_full: &str) -> Result<bool, Box<Error>> {
    match delta_or_full {
      "delta" => Ok(true),
      "full" => Ok(false),
      _ => Err(From::from("Package type must be either 'delta' or 'full'"))
    }
  }

  fn parse_name(filename_or_url: &str) -> Result<&str, Box<Error>> {
    if SCHEME.is_match(filename_or_url) {
      try!(Url::parse(filename_or_url));
      return Ok(filename_or_url)
    } else {
      let u = format!("file://{}", filename_or_url);
      try!(Url::parse(&u));
      return Ok(filename_or_url);
    }
  }

  fn parse_percentage(percent: &str) -> Result<i32, Box<Error>> {
    let n = try!(percent.trim_right_matches("%").parse::<i32>());
    if n > 100 || n < 0 {
      return Err(From::from("Percentage must be between 0 and 100 inclusive"));
    }

    return Ok(n);
  }

  pub fn parse(entry: &str) -> Result<Self, Box<Error>> {
    let e = entry.split_whitespace().collect::<Vec<_>>();

    return match e.len() {
      5 => {
        let (sha256, name, version, size, delta_or_full) = (e[0], e[1], e[2], e[3], e[4]);
        let mut ret = ReleaseEntry {
          sha256: [0; 32],
          is_delta: try!(ReleaseEntry::parse_delta_full(delta_or_full)),
          filename_or_url: try!(ReleaseEntry::parse_name(name)).to_owned(),
          version: try!(Version::parse(version)),
          length: try!(size.parse::<i64>()),
          percentage: 100,
        };

        try!(ReleaseEntry::parse_sha256(sha256, &mut ret));
        return Ok(ret);
      },
      6 => {
        let (sha256, name, version, size, delta_or_full, percent) = (e[0], e[1], e[2], e[3], e[4], e[5]);
        let mut ret = ReleaseEntry {
          sha256: [0; 32],
          is_delta: try!(ReleaseEntry::parse_delta_full(delta_or_full)),
          filename_or_url: try!(ReleaseEntry::parse_name(name)).to_owned(),
          version: try!(Version::parse(version)),
          length: try!(size.parse::<i64>()),
          percentage: try!(ReleaseEntry::parse_percentage(percent))
        };

        try!(ReleaseEntry::parse_sha256(sha256, &mut ret));
        return Ok(ret);
      },
      _ => Err(From::from("Invalid Release Entry string"))
    }
  }

  pub fn parse_entries(content: &str) -> Result<Vec<ReleaseEntry>, Box<Error>> {
    let mut was_error: Option<Box<Error>> = None;

    let r: Vec<ReleaseEntry> = content.split("\n").filter_map(|x| {
      let r = COMMENT.replace_all(x, "");
      if r.len() == 0 {
        return None;
      }

      match ReleaseEntry::parse(&r) {
        Err(err) => {
          was_error = Some(err);
          return None;
        },
        Ok(val) => Some(val)
      }
    }).collect();

    return match was_error {
      Some(err) => Err(err),
      None => Ok(r)
    };
  }
}

#[cfg(test)]
mod tests {
  use sha2::Sha256;
  use sha2::Digest;
  use super::ReleaseEntry;

  fn print_result(sum: &[u8], name: &str) {
    for byte in sum {
      print!("{:02x}", byte);
    }
    println!("\t{}", name);
  }

  #[test]
  fn create_a_release_entry() {
    let f = ReleaseEntry::default();
    assert_eq!(f.length, 42);
  }

  #[test]
  fn parse_should_read_valid_sha256() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full";
    let result = ReleaseEntry::parse(input).unwrap();

    assert_eq!(result.sha256[0], 0xE4);
    assert_eq!(result.sha256[1], 0x54);
    assert_eq!(result.sha256[31], 0x35);
  }

  #[test]
  fn parse_should_fail_invalid_sha256() {
    let input = "48fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_fail_very_invalid_sha256() {
    let input = "48Z myproject.7z 12345 full";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_fail_invalid_type() {
    let input = "48fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 foobar";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_set_delta_package() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta";
    let result = ReleaseEntry::parse(input).unwrap();

    assert_eq!(result.is_delta, true);

    let input2 = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full";
    let result2 = ReleaseEntry::parse(input2).unwrap();

    assert_eq!(result2.is_delta, false);
  }

  #[test]
  fn parse_should_accept_percentages() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta 45%";
    let result = ReleaseEntry::parse(input).unwrap();
    assert_eq!(result.percentage, 45);
  }

  #[test]
  fn parse_should_fail_giant_percentages() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta 145%";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_fail_negative_percentages() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta -145%";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_all_entries() {
    let input = "
# SHA256 of the file                                             Name       Version Size  [delta/full] release%
e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full
a4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-delta.7z 1.2.3 555 delta
b4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-beta.7z 2.0.0-beta.1 34567 full 5%";

    let result = ReleaseEntry::parse_entries(input).unwrap();
    assert_eq!(result.len(), 3);
  }

  #[test]
  fn stringify_a_sha256() {
    let mut sha = Sha256::default();
    sha.input("This is a test".as_bytes());

    let hash = sha.result();
    print_result(&hash, "SHA256");
    println!("Wat.");
  }
}
<commit_msg>URL Decode filenames<commit_after>use hex::*;
use regex::Regex;
use semver::Version;
use std::iter::*;
use std::error::{Error};
use url::{Url};
use url::percent_encoding::{percent_decode};

/* Example lines:

# SHA256 of the file                                             Name       Version Size  [delta/full] release%
e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full
a4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-delta.7z 123 delta
b4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-beta.7z 34567 full 5%
*/

#[derive(Debug)]
pub struct ReleaseEntry {
  pub sha256: [u8; 32],
  pub filename_or_url: String,
  pub version: Version,
  pub length: i64,
  pub is_delta: bool,
  pub percentage: i32,
}

impl Default for ReleaseEntry {
  fn default() -> ReleaseEntry {
    ReleaseEntry {
      filename_or_url: "Foobdar".to_owned(),
      version: Version::parse("1.0.0").unwrap(),
      is_delta: true,
      length: 42,
      sha256: [0; 32],
      percentage: 100,
    }
  }
}

lazy_static! {
  static ref SCHEME: Regex = Regex::new(r"^https:").unwrap();
}

lazy_static! {
  static ref COMMENT: Regex = Regex::new(r"#.*$").unwrap();
}

impl ReleaseEntry {
  fn parse_sha256(sha256: &str, to_fill: &mut ReleaseEntry) -> Result<bool, Box<Error>> {
    let ret = try!(sha256.from_hex());
    if ret.len() != 32 {
      return Err(From::from("SHA256 is malformed"));
    }

    for i in 0..32 { to_fill.sha256[i] = ret[i]; }
    return Ok(true);
  }

  fn parse_delta_full(delta_or_full: &str) -> Result<bool, Box<Error>> {
    match delta_or_full {
      "delta" => Ok(true),
      "full" => Ok(false),
      _ => Err(From::from("Package type must be either 'delta' or 'full'"))
    }
  }

  fn parse_name(filename_or_url: &str) -> Result<String, Box<Error>> {
    if SCHEME.is_match(filename_or_url) {
      try!(Url::parse(filename_or_url));
      return Ok(filename_or_url.to_owned())
    } else {
      let u = format!("file:///{}", filename_or_url);
      let url = try!(Url::parse(&u));

      let decoded = try!(percent_decode(url.path().as_bytes()).decode_utf8());
      return Ok(decoded.trim_left_matches("/").to_owned());
    }
  }

  fn parse_percentage(percent: &str) -> Result<i32, Box<Error>> {
    let n = try!(percent.trim_right_matches("%").parse::<i32>());
    if n > 100 || n < 0 {
      return Err(From::from("Percentage must be between 0 and 100 inclusive"));
    }

    return Ok(n);
  }

  pub fn parse(entry: &str) -> Result<Self, Box<Error>> {
    let e = entry.split_whitespace().collect::<Vec<_>>();

    return match e.len() {
      5 => {
        let (sha256, name, version, size, delta_or_full) = (e[0], e[1], e[2], e[3], e[4]);
        let mut ret = ReleaseEntry {
          sha256: [0; 32],
          is_delta: try!(ReleaseEntry::parse_delta_full(delta_or_full)),
          filename_or_url: try!(ReleaseEntry::parse_name(name)),
          version: try!(Version::parse(version)),
          length: try!(size.parse::<i64>()),
          percentage: 100,
        };

        try!(ReleaseEntry::parse_sha256(sha256, &mut ret));
        return Ok(ret);
      },
      6 => {
        let (sha256, name, version, size, delta_or_full, percent) = (e[0], e[1], e[2], e[3], e[4], e[5]);
        let mut ret = ReleaseEntry {
          sha256: [0; 32],
          is_delta: try!(ReleaseEntry::parse_delta_full(delta_or_full)),
          filename_or_url: try!(ReleaseEntry::parse_name(name)).to_owned(),
          version: try!(Version::parse(version)),
          length: try!(size.parse::<i64>()),
          percentage: try!(ReleaseEntry::parse_percentage(percent))
        };

        try!(ReleaseEntry::parse_sha256(sha256, &mut ret));
        return Ok(ret);
      },
      _ => Err(From::from("Invalid Release Entry string"))
    }
  }

  pub fn parse_entries(content: &str) -> Result<Vec<ReleaseEntry>, Box<Error>> {
    let mut was_error: Option<Box<Error>> = None;

    let r: Vec<ReleaseEntry> = content.split("\n").filter_map(|x| {
      let r = COMMENT.replace_all(x, "");
      if r.len() == 0 {
        return None;
      }

      match ReleaseEntry::parse(&r) {
        Err(err) => {
          was_error = Some(err);
          return None;
        },
        Ok(val) => Some(val)
      }
    }).collect();

    return match was_error {
      Some(err) => Err(err),
      None => Ok(r)
    };
  }
}

#[cfg(test)]
mod tests {
  use sha2::Sha256;
  use sha2::Digest;
  use super::ReleaseEntry;

  fn print_result(sum: &[u8], name: &str) {
    for byte in sum {
      print!("{:02x}", byte);
    }
    println!("\t{}", name);
  }

  #[test]
  fn create_a_release_entry() {
    let f = ReleaseEntry::default();
    assert_eq!(f.length, 42);
  }

  #[test]
  fn parse_should_read_valid_sha256() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full";
    let result = ReleaseEntry::parse(input).unwrap();

    assert_eq!(result.sha256[0], 0xE4);
    assert_eq!(result.sha256[1], 0x54);
    assert_eq!(result.sha256[31], 0x35);
  }

  #[test]
  fn parse_should_fail_invalid_sha256() {
    let input = "48fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_fail_very_invalid_sha256() {
    let input = "48Z myproject.7z 12345 full";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_fail_invalid_type() {
    let input = "48fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 foobar";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_set_delta_package() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta";
    let result = ReleaseEntry::parse(input).unwrap();

    assert_eq!(result.is_delta, true);

    let input2 = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full";
    let result2 = ReleaseEntry::parse(input2).unwrap();

    assert_eq!(result2.is_delta, false);
  }

  #[test]
  fn parse_should_accept_percentages() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta 45%";
    let result = ReleaseEntry::parse(input).unwrap();
    assert_eq!(result.percentage, 45);
  }

  #[test]
  fn parse_should_fail_giant_percentages() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta 145%";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn parse_should_fail_negative_percentages() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 delta -145%";
    ReleaseEntry::parse(input).unwrap_err();
  }

  #[test]
  fn url_encoded_filenames_should_end_up_decoded() {
    let input = "e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 my%20project.7z 1.2.3 12345 full";
    let result = ReleaseEntry::parse(input).unwrap();

    assert_eq!(result.filename_or_url, "my project.7z");
  }

  #[test]
  fn parse_all_entries() {
    let input = "
# SHA256 of the file                                             Name       Version Size  [delta/full] release%
e4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject.7z 1.2.3 12345 full
a4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-delta.7z 1.2.3 555 delta
b4548fba3f902e63e3fff36db7cbbd1837493e21c51f0751e51ee1483ddd0f35 myproject-beta.7z 2.0.0-beta.1 34567 full 5%";

    let result = ReleaseEntry::parse_entries(input).unwrap();
    assert_eq!(result.len(), 3);
  }

  #[test]
  fn stringify_a_sha256() {
    let mut sha = Sha256::default();
    sha.input("This is a test".as_bytes());

    let hash = sha.result();
    print_result(&hash, "SHA256");
    println!("Wat.");
  }
}
<|endoftext|>


<commit_before><commit_msg>Add a simple example to explain how works set_border for a single window<commit_after><|endoftext|>


<commit_before>extern crate byteorder;

use std;
use std::io::Write;
use self::byteorder::NativeEndian;
use self::byteorder::WriteBytesExt;

/// The remainder of the
pub trait Value {

    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &Self ) -> usize;

    /// Gets a zero.
    fn zero() -> Self;

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize;

    /// Converts the number of buckets into the value type.
    fn from_bucket_count( bucket_count: &usize ) -> Self;

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> Self;

    /// Converts the given index into the value type.
    fn from_index( index: usize ) -> Self;

    /// Decrements the value by one.
    fn decrement( &self ) -> Self;

    /// Serializes the value.
    fn serialize(
        &self,
        &mut Write
    ) -> Result<(), std::io::Error>;
}

/// Implements value trait for i32
impl Value for i32
{
    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &i32 ) -> usize {
        return ( self.clone() as usize ) % ( buckets.clone() as usize ) ;
    }

    /// Gets a zero.
    fn zero() -> i32 { return 0; }

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize { return self.clone() as usize; }

    /// Converts the specified value to a value that can be stored in the container.
    fn from_bucket_count( bucket_count: &usize ) -> i32 { return bucket_count.clone() as i32; }

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> i32 { return member_count as i32; }

    /// Converts the given value to index.
    fn from_index( index: usize ) -> i32 { return index as i32; }

    /// Decrements the value by one.
    fn decrement( &self ) -> i32 { return self - 1; }

    /// Serializes the value.
    fn serialize(
        &self,
        writer: &mut Write
    ) -> Result<(), std::io::Error>
    {
        writer.write_i32::<NativeEndian>( *self )?;
        Ok(())
    }
}

/// The index of the number of members in the set.
const SIZE_INDEX: usize = 1;

/// The index of the first bucket.
const FIRST_BUCKET_INDEX: usize = 2;

/// Defines how the data is stored in the scalar set.
 enum Storage<'a, TA, TB>
    where TB: 'a {

    /// The data is stored as a vector.
    Vector { data: Vec<TA> },

    /// The data is stored as a slice.
    Slice { data: &'a[TB] }
 }

pub struct RoScalarSet<'a, T>
where T: std::cmp::Ord + std::clone::Clone + Value + 'a {
    _storage: Storage<'a, T, T>
}

impl<'a, T> RoScalarSet<'a, T>
    where T: std::cmp::Ord + std::clone::Clone + Value + 'a {

    /// Returns a new integer hash set holding the specified values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn new<'b, 'c> (
            values: &'c[T]
    ) -> RoScalarSet<'b,T> {

        // Determine the number of buckets. We introduce a 5% overhead.
        let bucket_count: usize = ( values.len() as f64 * 0.05 ).ceil() as usize;
        let mut storage: Vec<T> = vec!( T::zero(); ( FIRST_BUCKET_INDEX + bucket_count + 1 + values.len() ) );

        // Store the number of buckets.
        let buckets = T::from_bucket_count( &bucket_count );
        storage[ 0 ] = buckets.clone();

        // Store the number of members.
        storage[ SIZE_INDEX ] = T::from_member_count( values.len() );

        // Count the values required for each bucket.
        let mut values_in_buckets: Vec<i32> = vec!( 0; bucket_count );
        for v in values {
            let bucket = v.get_bucket_index( &buckets );
            values_in_buckets[ bucket ] += 1;
        }

        // Set bucket pointers to point the end of each bucket.
        // They will be decrements one-by-one when the buckets are filled.
        let first_bucket: usize = FIRST_BUCKET_INDEX;
        let data_start: usize = FIRST_BUCKET_INDEX + bucket_count + 1;
        let mut previous_bucket_end = data_start;
        for b in 0..bucket_count  {

            // The end of the previous bucket is the start of the previous bucket.
            let index = previous_bucket_end + values_in_buckets[ b ].as_index();
            storage[ b + first_bucket ] = T::from_index( index );
            previous_bucket_end = index;
        }

        // Fix the end of the last bucket.
        storage[ first_bucket + bucket_count ] = T::from_index( storage.len() );

        // Put values into buckets.
        for v in values {

            // Determine bucket for the value.
            let bucket_id = v.get_bucket_index( &buckets );

            // Make room for the new value.
            storage[ bucket_id + first_bucket ] = storage[ bucket_id + first_bucket ].decrement();
            let value_index: usize = storage[ bucket_id + first_bucket ].as_index();
            storage[ value_index ] = v.clone();
        }

        // Sort each bucket to enable binary search.
        for b in 0..bucket_count  {

            // Determine the location of the bucket.
            let begin: usize = storage[ b + first_bucket ].as_index();
            let end: usize = storage[ b + first_bucket + 1 ].as_index();
            if end < begin {
                panic!( "Invalid bucket: {}", b );
            }

            // Get a splice for sorting.
            let ( _, remainder ) =  storage.split_at_mut( begin );
            let ( bucket,  _ )  = remainder.split_at_mut( end - begin );
            bucket.sort();
        }

        let storage: Storage<'b, T, T> = Storage::Vector { data: storage };
        return RoScalarSet { _storage: storage  };
    }

    /// Attaches an integer hash set to a slice holding the values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn attach<'b> (
            buffer: &'b[T]
    ) -> Result< ( RoScalarSet<'b, T>, &'b[T] ), &str > {

        // Determine the lenght of this scalar set.
        if buffer.len() < 4 {
            return Err( "The buffer is to small" );
        }
        let buckets = buffer[0].as_index();
        let values = buffer[SIZE_INDEX].as_index();
        let total_size = FIRST_BUCKET_INDEX + ( buckets + 1 ) + values;

        // Attach.
        let ( set, remainder ) = buffer.split_at( total_size );
        let storage: Storage<T, T> = Storage::Slice { data: set };
        return Ok( ( RoScalarSet { _storage: storage  }, remainder ) );
    }

    /// Checks whether the given value exists in the set or not.
    pub fn contains(
        &self,
        value: T
    ) -> bool {

        // Get the bucket associated with the value.
        let bucket = self.get_bucket( &value );

        // Locate the value.
        match bucket.binary_search( &value ) {
            Ok( _ ) => return true,
            Err(_) => return false,
        }
    }

    /// Gets the number of members in the set.
    pub fn size(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ SIZE_INDEX ].as_index();
    }

    /// Gets the number of buckets.
    pub fn bucket_count(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ 0 ].as_index();
    }

    /// Serializes the scalar set into the given writer.
    pub fn serialize<W>(
        &self,
        writer: &mut W
    ) -> Result<(), std::io::Error>
    where W: Write {

        // Write our intern
        let storage = self.borrow_storage();
        for v in storage {
            v.serialize( writer )?;
        }
        Ok(())
    }

    /// Gets a read-only slice containing the values of a bucket.
    fn get_bucket(
        &self,
        value: &T
    ) -> &[T] {

        // Determine the bucket.
        let storage = self.borrow_storage();
        let bucket_id: usize = value.get_bucket_index( &storage[ 0 ] );
        let bucket_index = bucket_id + FIRST_BUCKET_INDEX;
        let begin: usize = storage[ bucket_index ].as_index();
        let end: usize = storage[ ( bucket_index + 1 ) ].as_index();
        let  ( _, remainder ) = storage.split_at( begin );
        let  ( bucket, _ )  = remainder.split_at( end - begin );
        return bucket;
    }

    /// Borrows the storage for accessing the values.
    fn borrow_storage(
        &'a self
    ) -> &'a [T] {
        let s: &'a [T] = match &self._storage {
            &Storage::Vector { ref data } => data.as_slice(),
            &Storage::Slice { ref data } => data,

        };
        return s;
    }
}
<commit_msg>Fixes to comments<commit_after>extern crate byteorder;

use std;
use std::io::Write;
use self::byteorder::NativeEndian;
use self::byteorder::WriteBytesExt;

/// Represents a value in the scalar set.
/// The values must be able to store booking information
/// for managing the contents of the set. These requirements
/// are captured in this trait.
pub trait Value {

    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &Self ) -> usize;

    /// Gets a zero.
    fn zero() -> Self;

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize;

    /// Converts the number of buckets into the value type.
    fn from_bucket_count( bucket_count: &usize ) -> Self;

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> Self;

    /// Converts the given index into the value type.
    fn from_index( index: usize ) -> Self;

    /// Decrements the value by one.
    fn decrement( &self ) -> Self;

    /// Serializes the value.
    fn serialize(
        &self,
        &mut Write
    ) -> Result<(), std::io::Error>;
}

/// Implements Value trait for i32
impl Value for i32
{
    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &i32 ) -> usize {
        return ( self.clone() as usize ) % ( buckets.clone() as usize ) ;
    }

    /// Gets a zero.
    fn zero() -> i32 { return 0; }

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize { return self.clone() as usize; }

    /// Converts the specified value to a value that can be stored in the container.
    fn from_bucket_count( bucket_count: &usize ) -> i32 { return bucket_count.clone() as i32; }

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> i32 { return member_count as i32; }

    /// Converts the given value to index.
    fn from_index( index: usize ) -> i32 { return index as i32; }

    /// Decrements the value by one.
    fn decrement( &self ) -> i32 { return self - 1; }

    /// Serializes the value.
    fn serialize(
        &self,
        writer: &mut Write
    ) -> Result<(), std::io::Error>
    {
        writer.write_i32::<NativeEndian>( *self )?;
        Ok(())
    }
}

/// The index of the number of members in the set.
const SIZE_INDEX: usize = 1;

/// The index of the first bucket.
const FIRST_BUCKET_INDEX: usize = 2;

/// Defines how the data is stored in the scalar set.
 enum Storage<'a, TA, TB>
    where TB: 'a {

    /// The data is stored as a vector.
    Vector { data: Vec<TA> },

    /// The data is stored as a slice.
    Slice { data: &'a[TB] }
 }

/// Scalar set cabable of storing values with Value trait.
pub struct RoScalarSet<'a, T>
where T: std::cmp::Ord + std::clone::Clone + Value + 'a {
    _storage: Storage<'a, T, T>
}

impl<'a, T> RoScalarSet<'a, T>
    where T: std::cmp::Ord + std::clone::Clone + Value + 'a {

    /// Returns a new integer hash set holding the specified values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn new<'b, 'c> (
            values: &'c[T]
    ) -> RoScalarSet<'b,T> {

        // Determine the number of buckets. We introduce a 5% overhead.
        let bucket_count: usize = ( values.len() as f64 * 0.05 ).ceil() as usize;
        let mut storage: Vec<T> = vec!( T::zero(); ( FIRST_BUCKET_INDEX + bucket_count + 1 + values.len() ) );

        // Store the number of buckets.
        let buckets = T::from_bucket_count( &bucket_count );
        storage[ 0 ] = buckets.clone();

        // Store the number of members.
        storage[ SIZE_INDEX ] = T::from_member_count( values.len() );

        // Count the values required for each bucket.
        let mut values_in_buckets: Vec<i32> = vec!( 0; bucket_count );
        for v in values {
            let bucket = v.get_bucket_index( &buckets );
            values_in_buckets[ bucket ] += 1;
        }

        // Set bucket pointers to point the end of each bucket.
        // They will be decrements one-by-one when the buckets are filled.
        let first_bucket: usize = FIRST_BUCKET_INDEX;
        let data_start: usize = FIRST_BUCKET_INDEX + bucket_count + 1;
        let mut previous_bucket_end = data_start;
        for b in 0..bucket_count  {

            // The end of the previous bucket is the start of the previous bucket.
            let index = previous_bucket_end + values_in_buckets[ b ].as_index();
            storage[ b + first_bucket ] = T::from_index( index );
            previous_bucket_end = index;
        }

        // Fix the end of the last bucket.
        storage[ first_bucket + bucket_count ] = T::from_index( storage.len() );

        // Put values into buckets.
        for v in values {

            // Determine bucket for the value.
            let bucket_id = v.get_bucket_index( &buckets );

            // Make room for the new value.
            storage[ bucket_id + first_bucket ] = storage[ bucket_id + first_bucket ].decrement();
            let value_index: usize = storage[ bucket_id + first_bucket ].as_index();
            storage[ value_index ] = v.clone();
        }

        // Sort each bucket to enable binary search.
        for b in 0..bucket_count  {

            // Determine the location of the bucket.
            let begin: usize = storage[ b + first_bucket ].as_index();
            let end: usize = storage[ b + first_bucket + 1 ].as_index();
            if end < begin {
                panic!( "Invalid bucket: {}", b );
            }

            // Get a splice for sorting.
            let ( _, remainder ) =  storage.split_at_mut( begin );
            let ( bucket,  _ )  = remainder.split_at_mut( end - begin );
            bucket.sort();
        }

        let storage: Storage<'b, T, T> = Storage::Vector { data: storage };
        return RoScalarSet { _storage: storage  };
    }

    /// Attaches an integer hash set to a slice holding the values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn attach<'b> (
            buffer: &'b[T]
    ) -> Result< ( RoScalarSet<'b, T>, &'b[T] ), &str > {

        // Determine the length of this scalar set.
        if buffer.len() < 4 {
            return Err( "The buffer is to small" );
        }
        let buckets = buffer[0].as_index();
        let values = buffer[SIZE_INDEX].as_index();
        let total_size = FIRST_BUCKET_INDEX + ( buckets + 1 ) + values;

        // Attach.
        let ( set, remainder ) = buffer.split_at( total_size );
        let storage: Storage<T, T> = Storage::Slice { data: set };
        return Ok( ( RoScalarSet { _storage: storage  }, remainder ) );
    }

    /// Checks whether the given value exists in the set or not.
    pub fn contains(
        &self,
        value: T
    ) -> bool {

        // Get the bucket associated with the value.
        let bucket = self.get_bucket( &value );

        // Locate the value.
        match bucket.binary_search( &value ) {
            Ok( _ ) => return true,
            Err(_) => return false,
        }
    }

    /// Gets the number of members in the set.
    pub fn size(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ SIZE_INDEX ].as_index();
    }

    /// Gets the number of buckets.
    pub fn bucket_count(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ 0 ].as_index();
    }

    /// Serializes the scalar set into the given writer.
    pub fn serialize<W>(
        &self,
        writer: &mut W
    ) -> Result<(), std::io::Error>
    where W: Write {

        // Write our intern
        let storage = self.borrow_storage();
        for v in storage {
            v.serialize( writer )?;
        }
        Ok(())
    }

    /// Gets a read-only slice containing the values of a bucket.
    fn get_bucket(
        &self,
        value: &T
    ) -> &[T] {

        // Determine the bucket.
        let storage = self.borrow_storage();
        let bucket_id: usize = value.get_bucket_index( &storage[ 0 ] );
        let bucket_index = bucket_id + FIRST_BUCKET_INDEX;
        let begin: usize = storage[ bucket_index ].as_index();
        let end: usize = storage[ ( bucket_index + 1 ) ].as_index();
        let  ( _, remainder ) = storage.split_at( begin );
        let  ( bucket, _ )  = remainder.split_at( end - begin );
        return bucket;
    }

    /// Borrows the storage for accessing the values.
    fn borrow_storage(
        &'a self
    ) -> &'a [T] {
        let s: &'a [T] = match &self._storage {
            &Storage::Vector { ref data } => data.as_slice(),
            &Storage::Slice { ref data } => data,

        };
        return s;
    }
}
<|endoftext|>


<commit_before>use Graph;

use std::ops::Add;
use std::cmp::{PartialOrd, Ordering};
use std::iter::IteratorExt;
use std::hash::Hash;

use std::collections::hash_map::{HashMap, Hasher, Entry};
use std::collections::BinaryHeap;

use num;
use num::traits::Zero;

pub fn a_star<G: Graph>(graph: &G, start: G::Node, end: G::Node) -> Option<Vec<G::Node>>
    where G::Node: Hash<Hasher> + Eq + Clone,
          G::Neighbours: Iterator<Item=G::Node> + IteratorExt,
          G::Weight: Clone + Ord + PartialOrd + Add<Output=G::Weight> + Zero
{
    let mut dist_map: HashMap<_, PathNode<_, G::Weight>> = HashMap::new();

    let mut frontier = BinaryHeap::new();
    frontier.push(PathNode::new(start.clone(), None));

    while let Some(mut active_val) = frontier.pop() {
        // Check if a complete path has been found
        if active_val.node == end {
            // Follow the path back from the end node to the start node
            let mut path = vec![];
            loop {
                path.push(active_val.node.clone());
                active_val = match active_val.parent.clone() {
                    Some(v) => dist_map[v].clone(),
                    None => return Some(path),
                }
            }
        }

        // Insert the current value if it is better than any previous value inserted
        match dist_map.entry(active_val.node.clone()) {
            Entry::Occupied(mut e) => {
                if active_val.f_cost() < e.get().f_cost() { e.insert(active_val.clone()); }
                else { continue }
            },
            Entry::Vacant(e) => { e.insert(active_val.clone()); },
        }

        // Visit all the neighbours of the current node that have not already been added to the
        // distance map
        for node in graph.neighbours(&active_val.node).filter(|n| !dist_map.contains_key(n)) {
                // Get the cost of moving from the current node to the next node
                let move_cost = match graph.weight(&active_val.node, &node) {
                    Some(c) => c,
                    None => break,
                };

                let mut next_val = PathNode::new(node, Some(active_val.node.clone()));
                next_val.g_cost = active_val.g_cost.clone() + move_cost;
                next_val.h_cost = graph.heuristic(&next_val.node, &end);
                frontier.push(next_val);
        }
    }

    // No path to the end node could be found
    None
}

#[derive(Clone)]
struct PathNode<N, C> {
    node: N,
    parent: Option<N>,
    h_cost: C,
    g_cost: C,
}

impl<N, C: Zero + Add> PathNode<N, C> {
    pub fn new(node: N, parent: Option<N>) -> PathNode<N, C> {
        PathNode {
            node: node,
            h_cost: num::zero(),
            g_cost: num::zero(),
            parent: parent,
        }
    }
}

impl<N, C> PathNode<N, C> where C: Add<Output=C> + Clone {
    pub fn f_cost(&self) -> C {
        self.h_cost.clone() + self.g_cost.clone()
    }
}

impl<N, C> PartialEq for PathNode<N, C> where C: PartialEq + Add<Output=C> + Clone {
    fn eq(&self, other: &PathNode<N, C>) -> bool {
        self.f_cost() == other.f_cost()
    }
}
impl<N, C> Eq for PathNode<N, C> where C: PartialEq + Add<Output=C> + Clone {}

impl<N, C> PartialOrd for PathNode<N, C> where C: PartialOrd + Add<Output=C> + Clone {
    fn partial_cmp(&self, other: &PathNode<N, C>) -> Option<Ordering> {
        // Reverse the ordering so that it makes a min queue
        other.f_cost().partial_cmp(&self.f_cost())
    }
}
impl<N, C> Ord for PathNode<N, C> where C: Ord + Add<Output=C> + Clone {
    fn cmp(&self, other: &PathNode<N, C>) -> Ordering {
        // Reverse the ordering so that it makes a min queue
        other.f_cost().cmp(&self.f_cost())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::iter;
    use std::num::SignedInt;
    use Graph;

    struct Grid {
        width: u32,
        height: u32,
        data: Vec<bool>,
    }

    impl Grid {
        fn new(width: u32, height: u32) -> Grid {
            Grid {
                width: width,
                height: height,
                data: iter::repeat(false).take((width as usize * height as usize)).collect(),
            }
        }

        fn get(&self, index: &(u32, u32)) -> bool {
            let &(x, y) = index;
            if x >= self.width || y >= self.height {
                true
            }
            else {
                self.data[y as usize * self.width as usize + x as usize]
            }
        }

        fn set(&mut self, index: &(u32, u32), value: bool) {
            let &(x, y) = index;
            if x >= self.width || y >= self.height {
                panic!("Index out of bounds");
            }

            let index = y as usize * self.width as usize + x as usize;
            self.data[index] = value;
        }

    }

    struct Adjacent {
        pos: (u32, u32),
        i: usize,
        width: u32,
        height: u32,
    }

    impl Iterator for Adjacent {
        type Item = (u32, u32);

        fn next(&mut self) -> Option<(u32, u32)> {
            static POSSIBLE_MOVES: [(i32, i32); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];
            let (x, y) = self.pos;
            loop {
                if self.i > 3 {
                    return None;
                }
                let (dx, dy) = POSSIBLE_MOVES[self.i];
                let (x, y) = (x as i32 + dx, y as i32 + dy);
                self.i += 1;
                if x >= 0 && y >= 0 && (x as u32) < self.width && (y as u32) < self.height {
                    return Some((x as u32, y as u32))
                }
            }
        }
    }

    impl Graph for Grid {
        type Node = (u32, u32);
        type Weight = usize;
        type Neighbours = Adjacent;

        fn weight(&self, _: &(u32, u32), to: &(u32, u32)) -> Option<usize> {
            if self.get(to) { None } else { Some(10) }
        }

        fn neighbours(&self, node: &(u32, u32)) -> Adjacent {
            Adjacent {
                pos: *node,
                i: 0,
                width: self.width,
                height: self.height
            }
        }

        fn heuristic(&self, from: &(u32, u32), to: &(u32, u32)) -> usize {
            ((from.0 as i32 - to.0 as i32).abs() + (from.1 as i32 - to.0 as i32).abs()) as usize * 10
        }
    }

    #[test]
    fn test_pathfinding_basic() {
        let grid = Grid::new(5, 5);
        let path = a_star(&grid, (0, 0), (4, 0));
        assert!(path.is_some());
        assert_eq!(path.unwrap(), vec![(4, 0), (3, 0), (2, 0), (1, 0), (0, 0)]);
    }

    #[test]
    fn test_pathfinding_off_screen() {
        let grid = Grid::new(5, 5);
        let path = a_star(&grid, (0, 0), (5, 0));
        assert!(path.is_none());
    }

    #[test]
    fn test_pathfinding_possible() {
        let mut grid = Grid::new(400, 200);
        for y in (0..100) {
            grid.set(&(7, y), true);
        }

        let path = a_star(&grid, (2, 2), (300, 50));
        assert!(path.is_some());

        let path = path.unwrap();
        assert_eq!(path[0], (300, 50));
        assert_eq!(path.last().unwrap(), &(2, 2));

        for (&(x1, y1), &(x2, y2)) in path.iter().zip(path.iter().skip(1)) {
            assert!(grid.get(&(x1, y1)) == false);
            assert!(((x2 as i32 - x1 as i32) + (y2 as i32 - y1 as i32)).abs() == 1);
        }
    }

    #[test]
    fn test_pathfinding_impossible() {
        let mut grid = Grid::new(5, 5);
        grid.set(&(3, 0), true);
        grid.set(&(4, 1), true);
        let path = a_star(&grid, (0, 0), (4, 0));
        assert!(path.is_none());
    }
}
<commit_msg>Fix tabbing.<commit_after>use Graph;

use std::ops::Add;
use std::cmp::{PartialOrd, Ordering};
use std::iter::IteratorExt;
use std::hash::Hash;

use std::collections::hash_map::{HashMap, Hasher, Entry};
use std::collections::BinaryHeap;

use num;
use num::traits::Zero;

pub fn a_star<G: Graph>(graph: &G, start: G::Node, end: G::Node) -> Option<Vec<G::Node>>
    where G::Node: Hash<Hasher> + Eq + Clone,
          G::Neighbours: Iterator<Item=G::Node> + IteratorExt,
          G::Weight: Clone + Ord + PartialOrd + Add<Output=G::Weight> + Zero
{
    let mut dist_map: HashMap<_, PathNode<_, G::Weight>> = HashMap::new();

    let mut frontier = BinaryHeap::new();
    frontier.push(PathNode::new(start.clone(), None));

    while let Some(mut active_val) = frontier.pop() {
        // Check if a complete path has been found
        if active_val.node == end {
            // Follow the path back from the end node to the start node
            let mut path = vec![];
            loop {
                path.push(active_val.node.clone());
                active_val = match active_val.parent.clone() {
                    Some(v) => dist_map[v].clone(),
                    None => return Some(path),
                }
            }
        }

        // Insert the current value if it is better than any previous value inserted
        match dist_map.entry(active_val.node.clone()) {
            Entry::Occupied(mut e) => {
                if active_val.f_cost() < e.get().f_cost() { e.insert(active_val.clone()); }
                else { continue }
            },
            Entry::Vacant(e) => { e.insert(active_val.clone()); },
        }

        // Visit all the neighbours of the current node that have not already been added to the
        // distance map
        for node in graph.neighbours(&active_val.node).filter(|n| !dist_map.contains_key(n)) {
            // Get the cost of moving from the current node to the next node
            let move_cost = match graph.weight(&active_val.node, &node) {
                Some(c) => c,
                None => break,
            };

            let mut next_val = PathNode::new(node, Some(active_val.node.clone()));
            next_val.g_cost = active_val.g_cost.clone() + move_cost;
            next_val.h_cost = graph.heuristic(&next_val.node, &end);
            frontier.push(next_val);
        }
    }

    // No path to the end node could be found
    None
}

#[derive(Clone)]
struct PathNode<N, C> {
    node: N,
    parent: Option<N>,
    h_cost: C,
    g_cost: C,
}

impl<N, C: Zero + Add> PathNode<N, C> {
    pub fn new(node: N, parent: Option<N>) -> PathNode<N, C> {
        PathNode {
            node: node,
            h_cost: num::zero(),
            g_cost: num::zero(),
            parent: parent,
        }
    }
}

impl<N, C> PathNode<N, C> where C: Add<Output=C> + Clone {
    pub fn f_cost(&self) -> C {
        self.h_cost.clone() + self.g_cost.clone()
    }
}

impl<N, C> PartialEq for PathNode<N, C> where C: PartialEq + Add<Output=C> + Clone {
    fn eq(&self, other: &PathNode<N, C>) -> bool {
        self.f_cost() == other.f_cost()
    }
}
impl<N, C> Eq for PathNode<N, C> where C: PartialEq + Add<Output=C> + Clone {}

impl<N, C> PartialOrd for PathNode<N, C> where C: PartialOrd + Add<Output=C> + Clone {
    fn partial_cmp(&self, other: &PathNode<N, C>) -> Option<Ordering> {
        // Reverse the ordering so that it makes a min queue
        other.f_cost().partial_cmp(&self.f_cost())
    }
}
impl<N, C> Ord for PathNode<N, C> where C: Ord + Add<Output=C> + Clone {
    fn cmp(&self, other: &PathNode<N, C>) -> Ordering {
        // Reverse the ordering so that it makes a min queue
        other.f_cost().cmp(&self.f_cost())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::iter;
    use std::num::SignedInt;
    use Graph;

    struct Grid {
        width: u32,
        height: u32,
        data: Vec<bool>,
    }

    impl Grid {
        fn new(width: u32, height: u32) -> Grid {
            Grid {
                width: width,
                height: height,
                data: iter::repeat(false).take((width as usize * height as usize)).collect(),
            }
        }

        fn get(&self, index: &(u32, u32)) -> bool {
            let &(x, y) = index;
            if x >= self.width || y >= self.height {
                true
            }
            else {
                self.data[y as usize * self.width as usize + x as usize]
            }
        }

        fn set(&mut self, index: &(u32, u32), value: bool) {
            let &(x, y) = index;
            if x >= self.width || y >= self.height {
                panic!("Index out of bounds");
            }

            let index = y as usize * self.width as usize + x as usize;
            self.data[index] = value;
        }

    }

    struct Adjacent {
        pos: (u32, u32),
        i: usize,
        width: u32,
        height: u32,
    }

    impl Iterator for Adjacent {
        type Item = (u32, u32);

        fn next(&mut self) -> Option<(u32, u32)> {
            static POSSIBLE_MOVES: [(i32, i32); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];
            let (x, y) = self.pos;
            loop {
                if self.i > 3 {
                    return None;
                }
                let (dx, dy) = POSSIBLE_MOVES[self.i];
                let (x, y) = (x as i32 + dx, y as i32 + dy);
                self.i += 1;
                if x >= 0 && y >= 0 && (x as u32) < self.width && (y as u32) < self.height {
                    return Some((x as u32, y as u32))
                }
            }
        }
    }

    impl Graph for Grid {
        type Node = (u32, u32);
        type Weight = usize;
        type Neighbours = Adjacent;

        fn weight(&self, _: &(u32, u32), to: &(u32, u32)) -> Option<usize> {
            if self.get(to) { None } else { Some(10) }
        }

        fn neighbours(&self, node: &(u32, u32)) -> Adjacent {
            Adjacent {
                pos: *node,
                i: 0,
                width: self.width,
                height: self.height
            }
        }

        fn heuristic(&self, from: &(u32, u32), to: &(u32, u32)) -> usize {
            ((from.0 as i32 - to.0 as i32).abs() + (from.1 as i32 - to.0 as i32).abs()) as usize * 10
        }
    }

    #[test]
    fn test_pathfinding_basic() {
        let grid = Grid::new(5, 5);
        let path = a_star(&grid, (0, 0), (4, 0));
        assert!(path.is_some());
        assert_eq!(path.unwrap(), vec![(4, 0), (3, 0), (2, 0), (1, 0), (0, 0)]);
    }

    #[test]
    fn test_pathfinding_off_screen() {
        let grid = Grid::new(5, 5);
        let path = a_star(&grid, (0, 0), (5, 0));
        assert!(path.is_none());
    }

    #[test]
    fn test_pathfinding_possible() {
        let mut grid = Grid::new(400, 200);
        for y in (0..100) {
            grid.set(&(7, y), true);
        }

        let path = a_star(&grid, (2, 2), (300, 50));
        assert!(path.is_some());

        let path = path.unwrap();
        assert_eq!(path[0], (300, 50));
        assert_eq!(path.last().unwrap(), &(2, 2));

        for (&(x1, y1), &(x2, y2)) in path.iter().zip(path.iter().skip(1)) {
            assert!(grid.get(&(x1, y1)) == false);
            assert!(((x2 as i32 - x1 as i32) + (y2 as i32 - y1 as i32)).abs() == 1);
        }
    }

    #[test]
    fn test_pathfinding_impossible() {
        let mut grid = Grid::new(5, 5);
        grid.set(&(3, 0), true);
        grid.set(&(4, 1), true);
        let path = a_star(&grid, (0, 0), (4, 0));
        assert!(path.is_none());
    }
}
<|endoftext|>


<commit_before>use std::{fmt, iter};
use std::ops::{Index, IndexMut};
use std::str::FromStr;

use geom::{Geom, Point, Size, Matrix};

pub type Hint = Option<u8>;
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Side { In, Out }
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Edge { Line, Cross }

#[derive(Clone, Show, Eq, PartialEq)]
pub struct Board {
    size: Size,
    hint: Matrix<Hint>,
    side: Matrix<Option<Side>>,
    edge_v: Matrix<Option<Edge>>,
    edge_h: Matrix<Option<Edge>>
}

impl Board {
    pub fn new(size: Size) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new_empty(size, None, None);
        let side = Matrix::new_empty(size, Some(Side::Out), None);
        let edge_v = Matrix::new_empty(Size(size.0, size.1 + 1), Some(Edge::Cross), None);
        let edge_h = Matrix::new_empty(Size(size.0 + 1, size.1), Some(Edge::Cross), None);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    fn with_data(size: Size, hint: Vec<Hint>, side: Vec<Option<Side>>,
                 edge_v: Vec<Option<Edge>>, edge_h: Vec<Option<Edge>>) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new(size, None, hint);
        let side = Matrix::new(size, Some(Side::Out), side);
        let edge_v = Matrix::new(Size(size.0, size.1 + 1), Some(Edge::Cross), edge_v);
        let edge_h = Matrix::new(Size(size.0 + 1, size.1), Some(Edge::Cross), edge_h);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    pub fn hint(&self) -> &Matrix<Hint> { &self.hint }
    pub fn side(&self) -> &Matrix<Option<Side>> { &self.side }
    pub fn edge_h(&self) -> &Matrix<Option<Edge>> { &self.edge_h }
    pub fn edge_v(&self) -> &Matrix<Option<Edge>> { &self.edge_v }

    pub fn hint_mut(&mut self) -> &mut Matrix<Hint> { &mut self.hint }
    pub fn side_mut(&mut self) -> &mut Matrix<Option<Side>> { &mut self.side }
    pub fn edge_h_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_h }
    pub fn edge_v_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_v }
}

impl Geom for Board {
    fn size(&self) -> Size { self.size }
}

impl Index<Point> for Board {
    type Output = Hint;

    fn index(&self, p: &Point) -> &Hint {
        &self.hint[*p]
    }
}

impl IndexMut<Point> for Board {
    type Output = Hint;

    fn index_mut(&mut self, p: &Point) -> &mut Hint {
        &mut self.hint[*p]
    }
}

impl FromStr for Board {
    fn from_str(s: &str) -> Option<Board> {
        let mut mat = s.lines()
            .map(|l| l.trim_matches('\n'))
            .map(|l| l.chars().collect::<Vec<_>>())
            .skip_while(|l| l.is_empty())
            .collect::<Vec<_>>();

        while mat.last().map(|l| l.len()) == Some(0) {
            let _ = mat.pop();
        }

        fn parse_pat1(mat: Vec<Vec<char>>) -> Option<Board> {
            let rows = mat.iter()
                .enumerate()
                .filter(|&(_, cs)| cs[0] == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();
            let cols = mat[0].iter()
                .enumerate()
                .filter(|&(_, &c)| c == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();

            if rows.len() <= 1 { return None }
            if cols.len() <= 1 { return None }

            for &r in rows.iter() {
                if mat[r].iter().position(|&c| c == '+') != Some(cols[0]) {
                    return None
                }
                if mat[r].iter().rposition(|&c| c == '+') != Some(cols[cols.len() - 1]) {
                    return None
                }
                for &c in cols.iter() {
                    if mat[r].len() <= c {
                        return None
                    }
                    if mat[r][c] != '+' {
                        return None
                    }
                }
            }

            let mut edge_v = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for &c in cols.iter() {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .map(|row| row[c])
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '|') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_v.push(edge);
                }
            }

            let mut edge_h = vec!{};
            for &r in rows.iter() {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[r][cs + 1 .. ce]
                        .iter()
                        .cloned()
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '-') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_h.push(edge);
                }
            }

            let mut hint = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .flat_map(|row| row[cs + 1 .. ce].iter())
                        .cloned()
                        .collect::<String>();
                    let cell = match s.trim_matches(' ') {
                        "0" => Some(0),
                        "1" => Some(1),
                        "2" => Some(2),
                        "3" => Some(3),
                        _ => None
                    };
                    hint.push(cell);
                }
            }

            let size = Size((rows.len() - 1) as i32, (cols.len() - 1) as i32);
            let side = iter::repeat(None).take((rows.len() - 1) * (cols.len() - 1)).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        fn parse_pat2(mat: Vec<Vec<char>>) -> Option<Board> {
            let row = mat.len();
            if row == 0 { return None }
            let col = mat[0].len();
            if col == 0 { return None }
            if mat[1 ..].iter().any(|r| r.len() != col) { return None }

            let hint = mat.iter().flat_map(|line| {
                line.iter().filter_map(|&c| {
                    match c {
                        '0' => Some(Some(0)),
                        '1' => Some(Some(1)),
                        '2' => Some(Some(2)),
                        '3' => Some(Some(3)),
                        '_' => Some(None),
                        _ => None
                    }
                })
            }).collect::<Vec<_>>();
            if hint.len() != row * col { return None }

            let size = Size(row as i32, col as i32);
            let side = iter::repeat(None).take(row * col).collect();
            let edge_v = iter::repeat(None).take(row * (col + 1)).collect();
            let edge_h = iter::repeat(None).take((row + 1) * col).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        if mat[0].iter().any(|&c| c == '+') {
            parse_pat1(mat)
        } else {
            parse_pat2(mat)
        }
    }
}

struct Cross;
impl fmt::String for Cross {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "+")
    }
}

struct HEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for HEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let HEdge(board, p) = *self;
        match board.edge_h[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "-")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct VEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for VEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let VEdge(board, p) = *self;
        match board.edge_v[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "|")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct EdgeRow<'a>(&'a Board, i32);
impl<'a> fmt::String for EdgeRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let EdgeRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", Cross));
            try!(write!(f, "{}", HEdge(board, p)));
        }
        try!(write!(f, "{}", Cross));
        Ok(())
    }
}

struct CellRow<'a>(&'a Board, i32);
impl<'a> fmt::String for CellRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let CellRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", VEdge(board, p)));
            match board.hint[p] {
                Some(n) => try!(write!(f, "{}", n)),
                None => try!(write!(f, " "))
            }
        }
        try!(write!(f, "{}", VEdge(board, Point(r, board.column()))));
        Ok(())
    }
}

impl fmt::String for Board {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for r in (0 .. self.row()) {
            try!(writeln!(f, "{}", EdgeRow(self, r)));
            try!(writeln!(f, "{}", CellRow(self, r)));
        }
        try!(writeln!(f, "{}", EdgeRow(self, self.row())));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::Board;
    use geom::{Geom, Size, Point};

    #[test]
    fn parse() {
        let input = "123___
______
3_____
";
        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Size(3, 6), hint.size());
        assert_eq!(Some(1), hint[Point(0, 0)]);
        assert_eq!(Some(2), hint[Point(0, 1)]);
        assert_eq!(Some(3), hint[Point(0, 2)]);
        assert_eq!(None, hint[Point(0, 3)]);
        assert_eq!(None, hint[Point(0, 4)]);
        assert_eq!(None, hint[Point(0, 5)]);
        assert_eq!(None, hint[Point(1, 0)]);
        assert_eq!(None, hint[Point(1, 1)]);
        assert_eq!(None, hint[Point(1, 2)]);
        assert_eq!(None, hint[Point(1, 3)]);
        assert_eq!(None, hint[Point(1, 4)]);
        assert_eq!(None, hint[Point(1, 5)]);
        assert_eq!(Some(3), hint[Point(2, 0)]);
        assert_eq!(None, hint[Point(2, 1)]);
        assert_eq!(None, hint[Point(2, 2)]);
        assert_eq!(None, hint[Point(2, 3)]);
        assert_eq!(None, hint[Point(2, 4)]);
        assert_eq!(None, hint[Point(2, 5)]);

        assert_eq!(Some(&hint), hint.to_string().parse::<Board>().as_ref());

        assert_eq!(None, "1243".parse::<Board>());

        let input = "
+--+ +-+!!+asdf
+  + + +  +
|  |1|    |
|  | |  2 |
+  + + +  +
";
        let output = "+-+ +-+ +

+ + + + +
| |1|  2|
+ + + + +
";

        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Some(1), hint[Point(1, 1)]);
        assert_eq!(Some(2), hint[Point(1, 3)]);
        assert_eq!(output, hint.to_string());
    }
}
<commit_msg>board: support empty input<commit_after>use std::{fmt, iter};
use std::ops::{Index, IndexMut};
use std::str::FromStr;

use geom::{Geom, Point, Size, Matrix};

pub type Hint = Option<u8>;
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Side { In, Out }
#[derive(Copy, Clone, Show, Eq, PartialEq)]
pub enum Edge { Line, Cross }

#[derive(Clone, Show, Eq, PartialEq)]
pub struct Board {
    size: Size,
    hint: Matrix<Hint>,
    side: Matrix<Option<Side>>,
    edge_v: Matrix<Option<Edge>>,
    edge_h: Matrix<Option<Edge>>
}

impl Board {
    pub fn new(size: Size) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new_empty(size, None, None);
        let side = Matrix::new_empty(size, Some(Side::Out), None);
        let edge_v = Matrix::new_empty(Size(size.0, size.1 + 1), Some(Edge::Cross), None);
        let edge_h = Matrix::new_empty(Size(size.0 + 1, size.1), Some(Edge::Cross), None);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    fn with_data(size: Size, hint: Vec<Hint>, side: Vec<Option<Side>>,
                 edge_v: Vec<Option<Edge>>, edge_h: Vec<Option<Edge>>) -> Board {
        assert!(size.0 > 0 && size.1 > 0);
        let hint = Matrix::new(size, None, hint);
        let side = Matrix::new(size, Some(Side::Out), side);
        let edge_v = Matrix::new(Size(size.0, size.1 + 1), Some(Edge::Cross), edge_v);
        let edge_h = Matrix::new(Size(size.0 + 1, size.1), Some(Edge::Cross), edge_h);
        Board { size: size, hint: hint, side: side, edge_v: edge_v, edge_h: edge_h }
    }

    pub fn hint(&self) -> &Matrix<Hint> { &self.hint }
    pub fn side(&self) -> &Matrix<Option<Side>> { &self.side }
    pub fn edge_h(&self) -> &Matrix<Option<Edge>> { &self.edge_h }
    pub fn edge_v(&self) -> &Matrix<Option<Edge>> { &self.edge_v }

    pub fn hint_mut(&mut self) -> &mut Matrix<Hint> { &mut self.hint }
    pub fn side_mut(&mut self) -> &mut Matrix<Option<Side>> { &mut self.side }
    pub fn edge_h_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_h }
    pub fn edge_v_mut(&mut self) -> &mut Matrix<Option<Edge>> { &mut self.edge_v }
}

impl Geom for Board {
    fn size(&self) -> Size { self.size }
}

impl Index<Point> for Board {
    type Output = Hint;

    fn index(&self, p: &Point) -> &Hint {
        &self.hint[*p]
    }
}

impl IndexMut<Point> for Board {
    type Output = Hint;

    fn index_mut(&mut self, p: &Point) -> &mut Hint {
        &mut self.hint[*p]
    }
}

impl FromStr for Board {
    fn from_str(s: &str) -> Option<Board> {
        let mut mat = s.lines()
            .map(|l| l.trim_matches('\n'))
            .map(|l| l.chars().collect::<Vec<_>>())
            .skip_while(|l| l.is_empty())
            .collect::<Vec<_>>();

        while mat.last().map(|l| l.len()) == Some(0) {
            let _ = mat.pop();
        }

        if mat.len() == 0 { return None }

        fn parse_pat1(mat: Vec<Vec<char>>) -> Option<Board> {
            let rows = mat.iter()
                .enumerate()
                .filter(|&(_, cs)| cs[0] == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();
            let cols = mat[0].iter()
                .enumerate()
                .filter(|&(_, &c)| c == '+')
                .map(|(i, _)| i)
                .collect::<Vec<_>>();

            if rows.len() <= 1 { return None }
            if cols.len() <= 1 { return None }

            for &r in rows.iter() {
                if mat[r].iter().position(|&c| c == '+') != Some(cols[0]) {
                    return None
                }
                if mat[r].iter().rposition(|&c| c == '+') != Some(cols[cols.len() - 1]) {
                    return None
                }
                for &c in cols.iter() {
                    if mat[r].len() <= c {
                        return None
                    }
                    if mat[r][c] != '+' {
                        return None
                    }
                }
            }

            let mut edge_v = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for &c in cols.iter() {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .map(|row| row[c])
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '|') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_v.push(edge);
                }
            }

            let mut edge_h = vec!{};
            for &r in rows.iter() {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[r][cs + 1 .. ce]
                        .iter()
                        .cloned()
                        .collect::<String>();
                    let edge = if s.len() == 0 {
                        None
                    } else if s.chars().all(|c| c == 'x') {
                        Some(Edge::Cross)
                    } else if s.chars().all(|c| c == '-') {
                        Some(Edge::Line)
                    } else {
                        None
                    };
                    edge_h.push(edge);
                }
            }

            let mut hint = vec![];
            for (&rs, &re) in rows.iter().zip(rows[1 ..].iter()) {
                for (&cs, &ce) in cols.iter().zip(cols[1 ..].iter()) {
                    let s = mat[rs + 1 .. re]
                        .iter()
                        .flat_map(|row| row[cs + 1 .. ce].iter())
                        .cloned()
                        .collect::<String>();
                    let cell = match s.trim_matches(' ') {
                        "0" => Some(0),
                        "1" => Some(1),
                        "2" => Some(2),
                        "3" => Some(3),
                        _ => None
                    };
                    hint.push(cell);
                }
            }

            let size = Size((rows.len() - 1) as i32, (cols.len() - 1) as i32);
            let side = iter::repeat(None).take((rows.len() - 1) * (cols.len() - 1)).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        fn parse_pat2(mat: Vec<Vec<char>>) -> Option<Board> {
            let row = mat.len();
            if row == 0 { return None }
            let col = mat[0].len();
            if col == 0 { return None }
            if mat[1 ..].iter().any(|r| r.len() != col) { return None }

            let hint = mat.iter().flat_map(|line| {
                line.iter().filter_map(|&c| {
                    match c {
                        '0' => Some(Some(0)),
                        '1' => Some(Some(1)),
                        '2' => Some(Some(2)),
                        '3' => Some(Some(3)),
                        '_' => Some(None),
                        _ => None
                    }
                })
            }).collect::<Vec<_>>();
            if hint.len() != row * col { return None }

            let size = Size(row as i32, col as i32);
            let side = iter::repeat(None).take(row * col).collect();
            let edge_v = iter::repeat(None).take(row * (col + 1)).collect();
            let edge_h = iter::repeat(None).take((row + 1) * col).collect();
            Some(Board::with_data(size, hint, side, edge_v, edge_h))
        }

        if mat[0].iter().any(|&c| c == '+') {
            parse_pat1(mat)
        } else {
            parse_pat2(mat)
        }
    }
}

struct Cross;
impl fmt::String for Cross {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "+")
    }
}

struct HEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for HEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let HEdge(board, p) = *self;
        match board.edge_h[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "-")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct VEdge<'a>(&'a Board, Point);
impl<'a> fmt::String for VEdge<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let VEdge(board, p) = *self;
        match board.edge_v[p] {
            Some(Edge::Cross) => try!(write!(f, "x")),
            Some(Edge::Line) => try!(write!(f, "|")),
            None => try!(write!(f, " "))
        }
        Ok(())
    }
}

struct EdgeRow<'a>(&'a Board, i32);
impl<'a> fmt::String for EdgeRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let EdgeRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", Cross));
            try!(write!(f, "{}", HEdge(board, p)));
        }
        try!(write!(f, "{}", Cross));
        Ok(())
    }
}

struct CellRow<'a>(&'a Board, i32);
impl<'a> fmt::String for CellRow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let CellRow(board, r) = *self;
        for c in (0 .. board.column()) {
            let p = Point(r, c);
            try!(write!(f, "{}", VEdge(board, p)));
            match board.hint[p] {
                Some(n) => try!(write!(f, "{}", n)),
                None => try!(write!(f, " "))
            }
        }
        try!(write!(f, "{}", VEdge(board, Point(r, board.column()))));
        Ok(())
    }
}

impl fmt::String for Board {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for r in (0 .. self.row()) {
            try!(writeln!(f, "{}", EdgeRow(self, r)));
            try!(writeln!(f, "{}", CellRow(self, r)));
        }
        try!(writeln!(f, "{}", EdgeRow(self, self.row())));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::Board;
    use geom::{Geom, Size, Point};

    #[test]
    fn parse() {
        let input = "123___
______
3_____
";
        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Size(3, 6), hint.size());
        assert_eq!(Some(1), hint[Point(0, 0)]);
        assert_eq!(Some(2), hint[Point(0, 1)]);
        assert_eq!(Some(3), hint[Point(0, 2)]);
        assert_eq!(None, hint[Point(0, 3)]);
        assert_eq!(None, hint[Point(0, 4)]);
        assert_eq!(None, hint[Point(0, 5)]);
        assert_eq!(None, hint[Point(1, 0)]);
        assert_eq!(None, hint[Point(1, 1)]);
        assert_eq!(None, hint[Point(1, 2)]);
        assert_eq!(None, hint[Point(1, 3)]);
        assert_eq!(None, hint[Point(1, 4)]);
        assert_eq!(None, hint[Point(1, 5)]);
        assert_eq!(Some(3), hint[Point(2, 0)]);
        assert_eq!(None, hint[Point(2, 1)]);
        assert_eq!(None, hint[Point(2, 2)]);
        assert_eq!(None, hint[Point(2, 3)]);
        assert_eq!(None, hint[Point(2, 4)]);
        assert_eq!(None, hint[Point(2, 5)]);

        assert_eq!(Some(&hint), hint.to_string().parse::<Board>().as_ref());

        assert_eq!(None, "1243".parse::<Board>());

        let input = "
+--+ +-+!!+asdf
+  + + +  +
|  |1|    |
|  | |  2 |
+  + + +  +
";
        let output = "+-+ +-+ +

+ + + + +
| |1|  2|
+ + + + +
";

        let hint = input.parse::<Board>().unwrap();
        assert_eq!(Some(1), hint[Point(1, 1)]);
        assert_eq!(Some(2), hint[Point(1, 3)]);
        assert_eq!(output, hint.to_string());

        assert_eq!(None, "".parse::<Board>());
    }
}
<|endoftext|>


<commit_before>use common::*;
use data::value::*;
use data::packet::Packet;
use std::sync::Arc;
use std::io::Write;

use error::*;

pub trait Muxer {
    fn configure(&mut self) -> Result<()>;
    fn write_header(&mut self, buf: &mut Vec<u8>) -> Result<()>;
    fn write_packet(&mut self, buf: &mut Vec<u8>, pkt: Arc<Packet>) -> Result<()>;
    fn write_trailer(&mut self, buf: &mut Vec<u8>) -> Result<()>;

    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

pub struct Context {
    muxer: Box<Muxer>,
    writer: Box<Write>,
    buf: Vec<u8>,
}

impl Context {
    pub fn new<W: Write + 'static>(muxer: Box<Muxer>, writer: Box<W>) -> Self {
        Context {
            muxer: muxer,
            writer: writer,
            buf: Vec::new(),
        }
    }

    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    pub fn write_header(&mut self) -> Result<usize> {
        self.muxer.write_header(&mut self.buf)?;
        self.writer.write(&self.buf).map_err(|e| Error::Io(e))
    }

    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<usize> {
        self.muxer.write_packet(&mut self.buf, pkt)?;
        self.writer.write(&self.buf).map_err(|e| Error::Io(e))
    }

    pub fn write_trailer(&mut self) -> Result<usize> {
        self.muxer.write_trailer(&mut self.buf)?;
        self.writer.write(&self.buf).map_err(|e| Error::Io(e))
    }

    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
        where V: Into<Value<'a>> {
        self.muxer.set_option(key, val.into())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<Muxer>;
    fn describe<'a>(&'a self) -> &'a Descr;
}

pub trait Lookup {
    fn by_name(&self, name: &str) -> Option<&'static Descriptor>;
}

impl Lookup for [&'static Descriptor] {
    fn by_name(&self, name: &str) -> Option<&'static Descriptor> {
        self.iter()
            .find(|&&d| d.describe().name == name)
            .map(|v| *v)
    }
}
<commit_msg>ugly fix for muxer buffer management<commit_after>use common::*;
use data::value::*;
use data::packet::Packet;
use std::sync::Arc;
use std::io::Write;

use error::*;

pub trait Muxer {
    fn configure(&mut self) -> Result<()>;
    fn write_header(&mut self, buf: &mut Vec<u8>) -> Result<()>;
    fn write_packet(&mut self, buf: &mut Vec<u8>, pkt: Arc<Packet>) -> Result<()>;
    fn write_trailer(&mut self, buf: &mut Vec<u8>) -> Result<()>;

    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

pub struct Context {
    muxer: Box<Muxer>,
    writer: Box<Write>,
    buf: Vec<u8>,
}

impl Context {
    pub fn new<W: Write + 'static>(muxer: Box<Muxer>, writer: Box<W>) -> Self {
        Context {
            muxer: muxer,
            writer: writer,
            buf: Vec::new(),
        }
    }

    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    pub fn write_header(&mut self) -> Result<usize> {
        self.muxer.write_header(&mut self.buf)?;
        //FIXME: we should have proper management of the buffer's index
        match self.writer.write_all(&self.buf) {
          Ok(()) => {
            let len = self.buf.len();
            self.buf.clear();
            Ok(len)
          },
          Err(e) => Err(Error::Io(e)),
        }
    }

    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<usize> {
        self.muxer.write_packet(&mut self.buf, pkt)?;
        //FIXME: we should have proper management of the buffer's index
        match self.writer.write_all(&self.buf) {
          Ok(()) => {
            let len = self.buf.len();
            self.buf.clear();
            Ok(len)
          },
          Err(e) => Err(Error::Io(e)),
        }
    }

    pub fn write_trailer(&mut self) -> Result<usize> {
        self.muxer.write_trailer(&mut self.buf)?;
        //FIXME: we should have proper management of the buffer's index
        match self.writer.write_all(&self.buf) {
          Ok(()) => {
            let len = self.buf.len();
            self.buf.clear();
            Ok(len)
          },
          Err(e) => Err(Error::Io(e)),
        }
    }

    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
        where V: Into<Value<'a>> {
        self.muxer.set_option(key, val.into())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<Muxer>;
    fn describe<'a>(&'a self) -> &'a Descr;
}

pub trait Lookup {
    fn by_name(&self, name: &str) -> Option<&'static Descriptor>;
}

impl Lookup for [&'static Descriptor] {
    fn by_name(&self, name: &str) -> Option<&'static Descriptor> {
        self.iter()
            .find(|&&d| d.describe().name == name)
            .map(|v| *v)
    }
}
<|endoftext|>


<commit_before><commit_msg>update docs<commit_after><|endoftext|>