<commit_before>use std::borrow;
use std::error;
use std::fmt;
use std::result;

/// Convenience type alias for Liquid compiler errors
pub type Result<T> = result::Result<T, Error>;

/// `Result` extension methods for adapting third party errors to `Error`.
pub trait ResultLiquidChainExt<T> {
    /// Create an `Error` with `E` as the cause.
    fn chain(self, msg: &'static str) -> Result<T>;
    /// Create an `Error` with `E` as the cause.
    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String;
}

impl<T, E> ResultLiquidChainExt<T> for result::Result<T, E>
where
    E: error::Error + Send + Sync + 'static,
{
    fn chain(self, msg: &'static str) -> Result<T> {
        self.map_err(|err| Error::with_msg(msg).cause(err))
    }

    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| Error::with_msg(msg()).cause(err))
    }
}

/// Add context to a `liquid_error::Error`.
pub trait ResultLiquidExt<T> {
    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>;

    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String;

    /// Add state the current stack frame.
    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>;

    /// Add state the current stack frame.
    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String);
}

impl<T> ResultLiquidExt<T> for Result<T> {
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.trace(trace))
    }

    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| err.trace(trace()))
    }

    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.context(key, value))
    }

    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String),
    {
        let (key, value) = context();
        self.map_err(|err| err.context(key, value))
    }
}

/// Compiler error
#[derive(Clone, Debug)]
pub struct Error {
    inner: Box<InnerError>,
}

// Guts of `Error` here to keep `Error` small to avoid bloating the size of `Result<T>` in the
// success case.  There are already enough memory allocations below, one more shouldn't hurt.
#[derive(Clone, Debug)]
struct InnerError {
    msg: borrow::Cow<'static, str>,
    user_backtrace: Vec<Trace>,
    cause: Option<ErrorCause>,
}

impl Error {
    /// Create a new compiler error with the given message
    pub fn with_msg<S: Into<borrow::Cow<'static, str>>>(msg: S) -> Self {
        Self::with_msg_cow(msg.into())
    }

    fn with_msg_cow(msg: borrow::Cow<'static, str>) -> Self {
        let error = InnerError {
            msg,
            user_backtrace: vec![Trace::empty()],
            cause: None,
        };
        Self {
            inner: Box::new(error),
        }
    }

    /// Add a new call to the user-visible backtrace
    pub fn trace<T>(self, trace: T) -> Self
    where
        T: Into<borrow::Cow<'static, str>>,
    {
        self.trace_trace(trace.into())
    }

    fn trace_trace(mut self, trace: borrow::Cow<'static, str>) -> Self {
        let trace = Trace::new(trace);
        self.inner.user_backtrace.push(trace);
        self
    }

    /// Add context to the last traced call.
    ///
    /// Example context: Value that parameters from the `trace` evaluate to.
    pub fn context<K, V>(self, key: K, value: V) -> Self
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.context_cow_string(key.into(), value.into())
    }

    fn context_cow_string(
        mut self,
        key: borrow::Cow<'static, str>,
        value: borrow::Cow<'static, str>,
    ) -> Self {
        self.inner
            .user_backtrace
            .last_mut()
            .expect("always a trace available")
            .append_context(key, value);
        self
    }

    /// Add an external cause to the error for debugging purposes.
    pub fn cause<E: error::Error + Send + Sync + 'static>(self, cause: E) -> Self {
        let cause = Box::new(cause);
        self.cause_error(cause)
    }

    fn cause_error(mut self, cause: Box<error::Error + Send + Sync + 'static>) -> Self {
        let cause = Some(ErrorCause::new(cause));
        self.inner.cause = cause;
        self
    }
}

const ERROR_DESCRIPTION: &str = "liquid";

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.msg)?;
        for trace in &self.inner.user_backtrace {
            if let Some(trace) = trace.get_trace() {
                writeln!(f, "from: {}", trace)?;
            }
            if !trace.get_context().is_empty() {
                writeln!(f, "  with:")?;
            }
            for &(ref key, ref value) in trace.get_context() {
                writeln!(f, "    {}={}", key, value)?;
            }
        }
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        ERROR_DESCRIPTION
    }

    fn cause(&self) -> Option<&error::Error> {
        self.inner.cause.as_ref().and_then(|e| e.cause())
    }
}

/// User-visible call trace
#[derive(Clone, PartialEq, Eq, Debug, Default)]
struct Trace {
    trace: Option<borrow::Cow<'static, str>>,
    context: Vec<(borrow::Cow<'static, str>, borrow::Cow<'static, str>)>,
}

impl Trace {
    fn new(trace: borrow::Cow<'static, str>) -> Self {
        Self {
            trace: Some(trace),
            context: vec![],
        }
    }

    fn empty() -> Self {
        Self {
            trace: None,
            context: vec![],
        }
    }

    fn append_context(&mut self, key: borrow::Cow<'static, str>, value: borrow::Cow<'static, str>) {
        self.context.push((key, value));
    }

    fn get_trace(&self) -> Option<&str> {
        self.trace.as_ref().map(|s| s.as_ref())
    }

    fn get_context(&self) -> &[(borrow::Cow<'static, str>, borrow::Cow<'static, str>)] {
        self.context.as_ref()
    }
}

#[derive(Debug)]
enum ErrorCause {
    Generic(GenericError),
    Missing,
}

type GenericError = Box<error::Error + Send + Sync + 'static>;

impl ErrorCause {
    fn new(error: GenericError) -> Self {
        ErrorCause::Generic(error)
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ErrorCause::Generic(ref e) => Some(e.as_ref()),
            _ => None,
        }
    }
}

impl Clone for ErrorCause {
    fn clone(&self) -> Self {
        match *self {
            ErrorCause::Generic(_) | ErrorCause::Missing => ErrorCause::Missing,
        }
    }
}

impl fmt::Display for ErrorCause {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCause::Generic(ref e) => fmt::Display::fmt(e, f),
            ErrorCause::Missing => write!(f, "Unknown error"),
        }
    }
}
<commit_msg>refactor(error): Make intent clearer<commit_after>use std::borrow;
use std::error;
use std::fmt;
use std::result;

/// Convenience type alias for Liquid compiler errors
pub type Result<T> = result::Result<T, Error>;

/// `Result` extension methods for adapting third party errors to `Error`.
pub trait ResultLiquidChainExt<T> {
    /// Create an `Error` with `E` as the cause.
    fn chain(self, msg: &'static str) -> Result<T>;
    /// Create an `Error` with `E` as the cause.
    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String;
}

impl<T, E> ResultLiquidChainExt<T> for result::Result<T, E>
where
    E: error::Error + Send + Sync + 'static,
{
    fn chain(self, msg: &'static str) -> Result<T> {
        self.map_err(|err| Error::with_msg(msg).cause(err))
    }

    fn chain_with<F>(self, msg: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| Error::with_msg(msg()).cause(err))
    }
}

/// Add context to a `liquid_error::Error`.
pub trait ResultLiquidExt<T> {
    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>;

    /// Add a new stack frame to the `liquid_error::Error`.
    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String;

    /// Add state the current stack frame.
    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>;

    /// Add state the current stack frame.
    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String);
}

impl<T> ResultLiquidExt<T> for Result<T> {
    fn trace<S>(self, trace: S) -> Result<T>
    where
        S: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.trace(trace))
    }

    fn trace_with<F>(self, trace: F) -> Result<T>
    where
        F: FnOnce() -> String,
    {
        self.map_err(|err| err.trace(trace()))
    }

    fn context<K, V>(self, key: K, value: V) -> Result<T>
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.map_err(|err| err.context(key, value))
    }

    fn context_with<F>(self, context: F) -> Result<T>
    where
        F: FnOnce() -> (String, String),
    {
        let (key, value) = context();
        self.map_err(|err| err.context(key, value))
    }
}

/// Compiler error
#[derive(Clone, Debug)]
pub struct Error {
    inner: Box<InnerError>,
}

// Guts of `Error` here to keep `Error` small to avoid bloating the size of `Result<T>` in the
// success case.  There are already enough memory allocations below, one more shouldn't hurt.
#[derive(Clone, Debug)]
struct InnerError {
    msg: borrow::Cow<'static, str>,
    user_backtrace: Vec<Trace>,
    cause: Option<ClonableError>,
}

impl Error {
    /// Create a new compiler error with the given message
    pub fn with_msg<S: Into<borrow::Cow<'static, str>>>(msg: S) -> Self {
        Self::with_msg_cow(msg.into())
    }

    fn with_msg_cow(msg: borrow::Cow<'static, str>) -> Self {
        let error = InnerError {
            msg,
            user_backtrace: vec![Trace::empty()],
            cause: None,
        };
        Self {
            inner: Box::new(error),
        }
    }

    /// Add a new call to the user-visible backtrace
    pub fn trace<T>(self, trace: T) -> Self
    where
        T: Into<borrow::Cow<'static, str>>,
    {
        self.trace_trace(trace.into())
    }

    fn trace_trace(mut self, trace: borrow::Cow<'static, str>) -> Self {
        let trace = Trace::new(trace);
        self.inner.user_backtrace.push(trace);
        self
    }

    /// Add context to the last traced call.
    ///
    /// Example context: Value that parameters from the `trace` evaluate to.
    pub fn context<K, V>(self, key: K, value: V) -> Self
    where
        K: Into<borrow::Cow<'static, str>>,
        V: Into<borrow::Cow<'static, str>>,
    {
        self.context_cow_string(key.into(), value.into())
    }

    fn context_cow_string(
        mut self,
        key: borrow::Cow<'static, str>,
        value: borrow::Cow<'static, str>,
    ) -> Self {
        self.inner
            .user_backtrace
            .last_mut()
            .expect("always a trace available")
            .append_context(key, value);
        self
    }

    /// Add an external cause to the error for debugging purposes.
    pub fn cause<E: error::Error + Send + Sync + 'static>(self, cause: E) -> Self {
        let cause = Box::new(cause);
        self.cause_error(cause)
    }

    fn cause_error(mut self, cause: Box<error::Error + Send + Sync + 'static>) -> Self {
        let cause = Some(ClonableError::new(cause));
        self.inner.cause = cause;
        self
    }
}

const ERROR_DESCRIPTION: &str = "liquid";

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}: {}", ERROR_DESCRIPTION, self.inner.msg)?;
        for trace in &self.inner.user_backtrace {
            if let Some(trace) = trace.get_trace() {
                writeln!(f, "from: {}", trace)?;
            }
            if !trace.get_context().is_empty() {
                writeln!(f, "  with:")?;
            }
            for &(ref key, ref value) in trace.get_context() {
                writeln!(f, "    {}={}", key, value)?;
            }
        }
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        ERROR_DESCRIPTION
    }

    fn cause(&self) -> Option<&error::Error> {
        self.inner.cause.as_ref().and_then(|e| e.cause())
    }
}

/// User-visible call trace
#[derive(Clone, PartialEq, Eq, Debug, Default)]
struct Trace {
    trace: Option<borrow::Cow<'static, str>>,
    context: Vec<(borrow::Cow<'static, str>, borrow::Cow<'static, str>)>,
}

impl Trace {
    fn new(trace: borrow::Cow<'static, str>) -> Self {
        Self {
            trace: Some(trace),
            context: vec![],
        }
    }

    fn empty() -> Self {
        Self {
            trace: None,
            context: vec![],
        }
    }

    fn append_context(&mut self, key: borrow::Cow<'static, str>, value: borrow::Cow<'static, str>) {
        self.context.push((key, value));
    }

    fn get_trace(&self) -> Option<&str> {
        self.trace.as_ref().map(|s| s.as_ref())
    }

    fn get_context(&self) -> &[(borrow::Cow<'static, str>, borrow::Cow<'static, str>)] {
        self.context.as_ref()
    }
}

#[derive(Debug)]
enum ClonableError {
    Original(BoxedError),
    Missing,
}

type BoxedError = Box<error::Error + Send + Sync + 'static>;

impl ClonableError {
    fn new(error: BoxedError) -> Self {
        ClonableError::Original(error)
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ClonableError::Original(ref e) => Some(e.as_ref()),
            _ => None,
        }
    }
}

impl Clone for ClonableError {
    fn clone(&self) -> Self {
        match *self {
            ClonableError::Original(_) | ClonableError::Missing => ClonableError::Missing,
        }
    }
}

impl fmt::Display for ClonableError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ClonableError::Original(ref e) => fmt::Display::fmt(e, f),
            ClonableError::Missing => write!(f, "Unknown error"),
        }
    }
}
<|endoftext|>


<commit_before>use WindowId;

pub struct Draw {
    /// A list of commands that describe how to draw the frames for each window.
    pub commands: Vec<(WindowId, Command)>,
}

pub enum Command {
    Clear {
        rect: Option<&glium::Rect>,
        color: Option<(f32, f32, f32, f32)>,
        color_srgb: bool,
        depth: Option<f32>,
        stencil: Option<i32>,
    },

    Draw {
        vertex_buffer: V,
        index_buffer: I,
        program: &glium::Program,
        uniforms: &U,
        draw_parameters: &glium::DrawParameters,
    },
}
<commit_msg>Remove unused draw module<commit_after><|endoftext|>


<commit_before>//! `las` file management.

use std::f64;
use std::fs;
use std::io::{BufReader, BufWriter, Seek, Read, Write};
use std::path::Path;

use byteorder::{LittleEndian, WriteBytesExt};

use Result;
use error::Error;
use header::Header;
use io::write_zeros;
use point::Point;
use scale::descale;
use stream::Stream;
use vlr::Vlr;

/// A las file.
#[derive(Debug, PartialEq)]
pub struct File {
    header: Header,
    vlrs: Vec<Vlr>,
    points: Vec<Point>,
}

impl File {
    /// Reads a las file from the filesystem.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::from_path("data/1.0_0.las").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<File> {
        let reader = BufReader::new(try!(fs::File::open(path)));
        File::read_from(reader)
    }

    /// Reads a las file from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use las::file::File;
    /// let reader = fs::File::open("data/1.0_0.las").unwrap();
    /// let file = File::read_from(reader).unwrap();
    /// ```
    pub fn read_from<R: Read + Seek>(reader: R) -> Result<File> {
        let mut file = File::new();
        let mut stream = try!(Stream::new(reader));
        file.header = stream.header();
        file.vlrs = (*stream.vlrs()).clone();
        file.points.reserve(stream.npoints() as usize);
        loop {
            match try!(stream.next_point()) {
                Some(point) => file.points.push(point),
                None => break,
            }
        }
        Ok(file)
    }

    /// Creates a new, empty las file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::new();
    /// ```
    pub fn new() -> File {
        File {
            header: Header::new(),
            vlrs: Vec::new(),
            points: Vec::new(),
        }
    }

    /// Set the scale factors on a file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::new().scale_factors(0.01, 0.01, 0.01);
    /// ```
    pub fn scale_factors(mut self,
                         x_scale_factor: f64,
                         y_scale_factor: f64,
                         z_scale_factor: f64)
                         -> File {
        self.header.x_scale_factor = x_scale_factor;
        self.header.y_scale_factor = y_scale_factor;
        self.header.z_scale_factor = z_scale_factor;
        self
    }

    /// Set the offset values for a file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::new().offsets(1000.0, 2000.0, 100.0);
    /// ```
    pub fn offsets(mut self, x_offset: f64, y_offset: f64, z_offset: f64) -> File {
        self.header.x_offset = x_offset;
        self.header.y_offset = y_offset;
        self.header.z_offset = z_offset;
        self
    }

    /// Returns a reference to a vector of this file's points.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::from_path("data/1.0_0.las").unwrap();
    /// let points = file.points();
    /// ```
    pub fn points(&self) -> &Vec<Point> {
        &self.points
    }

    /// Adds a point to this lasfile.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// use las::point::Point;
    /// let mut file = File::new();
    /// let point = Point::new();
    /// file.add_point(point);
    /// ```
    pub fn add_point(&mut self, point: Point) {
        self.points.push(point);
    }

    /// Writes out this las file to a `Path`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::remove_file;
    /// use las::file::File;
    /// let mut file = File::new();
    /// file.to_path("temp.las").unwrap();
    /// remove_file("temp.las");
    /// ```
    pub fn to_path<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
        let ref mut writer = BufWriter::new(try!(fs::File::create(path)));
        self.write_to(writer)
    }

    /// Writes this las file to a `Write`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::Cursor;
    /// use las::file::File;
    /// let mut file = File::from_path("data/1.0_0.las").unwrap();
    /// let ref mut cursor = Cursor::new(Vec::new());
    /// file.write_to(cursor).unwrap();
    /// ```
    pub fn write_to<W: Write>(&mut self, writer: &mut W) -> Result<()> {
        self.header.calculate_size();
        self.header.number_of_point_records = self.points.len() as u32;
        self.header.offset_to_point_data = self.header.header_size as u32 +
                                           self.vlrs.iter().fold(0, |a, v| a + v.len());
        self.header.point_data_record_length = self.header.point_data_format.record_length();

        let mut number_of_points_by_return = [0u32; 5];
        let mut x_min = f64::MAX;
        let mut y_min = f64::MAX;
        let mut z_min = f64::MAX;
        let mut x_max = f64::MIN;
        let mut y_max = f64::MIN;
        let mut z_max = f64::MIN;
        for point in &self.points {
            let return_number = point.return_number.as_u8();
            if return_number > 0 {
                number_of_points_by_return[(return_number - 1) as usize] += 1;
            }
            if point.x < x_min {
                x_min = point.x;
            }
            if point.y < y_min {
                y_min = point.y;
            }
            if point.z < z_min {
                z_min = point.z;
            }
            if point.x > x_max {
                x_max = point.x;
            }
            if point.y > y_max {
                y_max = point.y;
            }
            if point.z > z_max {
                z_max = point.z;
            }
        }
        self.header.x_min = x_min;
        self.header.y_min = y_min;
        self.header.z_min = z_min;
        self.header.x_max = x_max;
        self.header.y_max = y_max;
        self.header.z_max = z_max;

        let mut bytes_written = try!(self.header.write_to(writer)) as usize;
        if bytes_written < self.header.header_size as usize {
            bytes_written += try!(write_zeros(writer,
                                              self.header.header_size as usize - bytes_written));
        }
        for vlr in &self.vlrs {
            bytes_written += try!(vlr.write_to(writer)) as usize;
        }
        if bytes_written < self.header.offset_to_point_data as usize {
            try!(write_zeros(writer,
                             self.header.offset_to_point_data as usize - bytes_written));
        }
        for point in &self.points {
            try!(self.write_point_to(writer, point));
        }
        Ok(())
    }

    fn write_point_to<W: Write>(&self, writer: &mut W, point: &Point) -> Result<()> {
        try!(writer.write_i32::<LittleEndian>(descale(point.x,
                                                      self.header.x_scale_factor,
                                                      self.header.x_offset)));
        try!(writer.write_i32::<LittleEndian>(descale(point.y,
                                                      self.header.y_scale_factor,
                                                      self.header.y_offset)));
        try!(writer.write_i32::<LittleEndian>(descale(point.z,
                                                      self.header.z_scale_factor,
                                                      self.header.z_offset)));
        try!(writer.write_u16::<LittleEndian>(point.intensity));
        let byte = point.return_number.as_u8() + (point.number_of_returns.as_u8() << 3) +
                   (point.scan_direction.as_u8() << 6) +
                   ((point.edge_of_flight_line as u8) << 7);
        try!(writer.write_u8(byte));
        let byte = point.classification.as_u8() + ((point.synthetic as u8) << 5) +
                   ((point.key_point as u8) << 6) +
                   ((point.withheld as u8) << 7);
        try!(writer.write_u8(byte));
        try!(writer.write_i8(point.scan_angle_rank));
        try!(writer.write_u8(point.user_data));
        try!(writer.write_u16::<LittleEndian>(point.point_source_id));
        if self.header.point_data_format.has_time() {
            match point.gps_time {
                Some(gps_time) => try!(writer.write_f64::<LittleEndian>(gps_time)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "gps_time".to_string()))
                }
            }
        }
        if self.header.point_data_format.has_color() {
            match point.red {
                Some(red) => try!(writer.write_u16::<LittleEndian>(red)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "red".to_string()))
                }
            }
            match point.green {
                Some(green) => try!(writer.write_u16::<LittleEndian>(green)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "green".to_string()))
                }
            }
            match point.blue {
                Some(blue) => try!(writer.write_u16::<LittleEndian>(blue)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "blue".to_string()))
                }
            }
        }
        match point.extra_bytes {
            Some(ref bytes) => try!(writer.write_all(&bytes[..])),
            None => {}
        }
        Ok(())
    }
}

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

    use std::fs::remove_file;
    use std::io::Cursor;
    use std::path::Path;

    use point::Point;

    fn roundtrip<P: AsRef<Path>>(path: P) {
        let mut lasfile = File::from_path(path).unwrap();
        let ref mut cursor = Cursor::new(Vec::new());
        lasfile.write_to(cursor).unwrap();
        cursor.set_position(0);
        let lasfile2 = File::read_from(cursor).unwrap();
        assert_eq!(lasfile, lasfile2);
    }

    #[test]
    fn roundtrip_1_0_0() {
        roundtrip("data/1.0_0.las");
    }

    #[test]
    fn roundtrip_1_0_1() {
        roundtrip("data/1.0_1.las");
    }

    #[test]
    fn roundtrip_1_1_0() {
        roundtrip("data/1.1_0.las");
    }

    #[test]
    fn roundtrip_1_1_1() {
        roundtrip("data/1.1_1.las");
    }

    #[test]
    fn roundtrip_1_2_0() {
        roundtrip("data/1.2_0.las");
    }

    #[test]
    fn roundtrip_1_2_1() {
        roundtrip("data/1.2_1.las");
    }

    #[test]
    fn roundtrip_1_2_2() {
        roundtrip("data/1.2_2.las");
    }

    #[test]
    fn roundtrip_1_2_3() {
        roundtrip("data/1.2_3.las");
    }

    /// This file is good as it exercieses a weird use case, but the test fails at the moment. I'm
    /// not sure why, so I'm going to keep it around but ignore it.
    #[test]
    #[ignore]
    fn roundtrip_extrabytes() {
        roundtrip("data/extrabytes.las");
    }

    #[test]
    fn point_format_1_has_gps_time() {
        let lasfile = File::from_path("data/1.0_1.las").unwrap();
        let ref point = lasfile.points()[0];
        assert!(point.gps_time.is_some());
    }

    #[test]
    fn point_format_2_has_color() {
        let lasfile = File::from_path("data/1.2_2.las").unwrap();
        let ref point = lasfile.points()[0];
        assert!(point.red.is_some());
        assert!(point.green.is_some());
        assert!(point.blue.is_some());
    }

    #[test]
    fn write_one_point() {
        let mut point = Point::new();
        point.x = 1.0;
        point.y = 2.0;
        point.z = 3.0;
        let mut lasfile = File::new();
        lasfile.add_point(point);
        lasfile.to_path("temp.las").unwrap();

        let lasfile = File::from_path("temp.las").unwrap();
        let ref point = lasfile.points()[0];
        assert_eq!(1.0, point.x);
        assert_eq!(2.0, point.y);
        assert_eq!(3.0, point.z);

        remove_file("temp.las").unwrap();
    }
}
<commit_msg>Add auto-offset feature<commit_after>//! `las` file management.

use std::f64;
use std::fs;
use std::io::{BufReader, BufWriter, Seek, Read, Write};
use std::path::Path;

use byteorder::{LittleEndian, WriteBytesExt};

use Result;
use error::Error;
use header::Header;
use io::write_zeros;
use point::Point;
use scale::descale;
use stream::Stream;
use vlr::Vlr;

/// A las file.
#[derive(Debug, PartialEq)]
pub struct File {
    header: Header,
    vlrs: Vec<Vlr>,
    points: Vec<Point>,
    auto_offsets: bool,
}

impl File {
    /// Reads a las file from the filesystem.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::from_path("data/1.0_0.las").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<File> {
        let reader = BufReader::new(try!(fs::File::open(path)));
        File::read_from(reader)
    }

    /// Reads a las file from a `Read`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs;
    /// use las::file::File;
    /// let reader = fs::File::open("data/1.0_0.las").unwrap();
    /// let file = File::read_from(reader).unwrap();
    /// ```
    pub fn read_from<R: Read + Seek>(reader: R) -> Result<File> {
        let mut file = File::new();
        let mut stream = try!(Stream::new(reader));
        file.header = stream.header();
        file.vlrs = (*stream.vlrs()).clone();
        file.points.reserve(stream.npoints() as usize);
        loop {
            match try!(stream.next_point()) {
                Some(point) => file.points.push(point),
                None => break,
            }
        }
        Ok(file)
    }

    /// Creates a new, empty las file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::new();
    /// ```
    pub fn new() -> File {
        File {
            header: Header::new(),
            vlrs: Vec::new(),
            points: Vec::new(),
            auto_offsets: false,
        }
    }

    /// Sets the scale factors on a file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::new().scale_factors(0.01, 0.01, 0.01);
    /// ```
    pub fn scale_factors(mut self,
                         x_scale_factor: f64,
                         y_scale_factor: f64,
                         z_scale_factor: f64)
                         -> File {
        self.header.x_scale_factor = x_scale_factor;
        self.header.y_scale_factor = y_scale_factor;
        self.header.z_scale_factor = z_scale_factor;
        self
    }

    /// Sets the offset values for a file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::new().offsets(1000.0, 2000.0, 100.0);
    /// ```
    pub fn offsets(mut self, x_offset: f64, y_offset: f64, z_offset: f64) -> File {
        self.header.x_offset = x_offset;
        self.header.y_offset = y_offset;
        self.header.z_offset = z_offset;
        self
    }

    /// Enables auto-offsetting.
    ///
    /// If auto-offsetting is enabled, this file will set the header offset values to sensible
    /// values before writing anything. This is usually easier than calculating the offsets
    /// yourself.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::new().auto_offsets(true);
    /// ```
    pub fn auto_offsets(mut self, enable: bool) -> File {
        self.auto_offsets = enable;
        self
    }

    /// Returns a reference to a vector of this file's points.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// let file = File::from_path("data/1.0_0.las").unwrap();
    /// let points = file.points();
    /// ```
    pub fn points(&self) -> &Vec<Point> {
        &self.points
    }

    /// Adds a point to this lasfile.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::file::File;
    /// use las::point::Point;
    /// let mut file = File::new();
    /// let point = Point::new();
    /// file.add_point(point);
    /// ```
    pub fn add_point(&mut self, point: Point) {
        self.points.push(point);
    }

    /// Writes out this las file to a `Path`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::remove_file;
    /// use las::file::File;
    /// let mut file = File::new();
    /// file.to_path("temp.las").unwrap();
    /// remove_file("temp.las");
    /// ```
    pub fn to_path<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
        let ref mut writer = BufWriter::new(try!(fs::File::create(path)));
        self.write_to(writer)
    }

    /// Writes this las file to a `Write`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::Cursor;
    /// use las::file::File;
    /// let mut file = File::from_path("data/1.0_0.las").unwrap();
    /// let ref mut cursor = Cursor::new(Vec::new());
    /// file.write_to(cursor).unwrap();
    /// ```
    pub fn write_to<W: Write>(&mut self, writer: &mut W) -> Result<()> {
        self.header.calculate_size();
        self.header.number_of_point_records = self.points.len() as u32;
        self.header.offset_to_point_data = self.header.header_size as u32 +
                                           self.vlrs.iter().fold(0, |a, v| a + v.len());
        self.header.point_data_record_length = self.header.point_data_format.record_length();

        let mut number_of_points_by_return = [0u32; 5];
        let mut x_min = f64::MAX;
        let mut y_min = f64::MAX;
        let mut z_min = f64::MAX;
        let mut x_max = f64::MIN;
        let mut y_max = f64::MIN;
        let mut z_max = f64::MIN;
        for point in &self.points {
            let return_number = point.return_number.as_u8();
            if return_number > 0 {
                number_of_points_by_return[(return_number - 1) as usize] += 1;
            }
            if point.x < x_min {
                x_min = point.x;
            }
            if point.y < y_min {
                y_min = point.y;
            }
            if point.z < z_min {
                z_min = point.z;
            }
            if point.x > x_max {
                x_max = point.x;
            }
            if point.y > y_max {
                y_max = point.y;
            }
            if point.z > z_max {
                z_max = point.z;
            }
        }
        self.header.x_min = x_min;
        self.header.y_min = y_min;
        self.header.z_min = z_min;
        self.header.x_max = x_max;
        self.header.y_max = y_max;
        self.header.z_max = z_max;

        if self.auto_offsets {
            self.header.x_offset = (x_min + x_max) / 2.0;
            self.header.y_offset = (y_min + y_max) / 2.0;
            self.header.z_offset = (z_min + z_max) / 2.0;
        }

        let mut bytes_written = try!(self.header.write_to(writer)) as usize;
        if bytes_written < self.header.header_size as usize {
            bytes_written += try!(write_zeros(writer,
                                              self.header.header_size as usize - bytes_written));
        }
        for vlr in &self.vlrs {
            bytes_written += try!(vlr.write_to(writer)) as usize;
        }
        if bytes_written < self.header.offset_to_point_data as usize {
            try!(write_zeros(writer,
                             self.header.offset_to_point_data as usize - bytes_written));
        }
        for point in &self.points {
            try!(self.write_point_to(writer, point));
        }
        Ok(())
    }

    fn write_point_to<W: Write>(&self, writer: &mut W, point: &Point) -> Result<()> {
        try!(writer.write_i32::<LittleEndian>(descale(point.x,
                                                      self.header.x_scale_factor,
                                                      self.header.x_offset)));
        try!(writer.write_i32::<LittleEndian>(descale(point.y,
                                                      self.header.y_scale_factor,
                                                      self.header.y_offset)));
        try!(writer.write_i32::<LittleEndian>(descale(point.z,
                                                      self.header.z_scale_factor,
                                                      self.header.z_offset)));
        try!(writer.write_u16::<LittleEndian>(point.intensity));
        let byte = point.return_number.as_u8() + (point.number_of_returns.as_u8() << 3) +
                   (point.scan_direction.as_u8() << 6) +
                   ((point.edge_of_flight_line as u8) << 7);
        try!(writer.write_u8(byte));
        let byte = point.classification.as_u8() + ((point.synthetic as u8) << 5) +
                   ((point.key_point as u8) << 6) +
                   ((point.withheld as u8) << 7);
        try!(writer.write_u8(byte));
        try!(writer.write_i8(point.scan_angle_rank));
        try!(writer.write_u8(point.user_data));
        try!(writer.write_u16::<LittleEndian>(point.point_source_id));
        if self.header.point_data_format.has_time() {
            match point.gps_time {
                Some(gps_time) => try!(writer.write_f64::<LittleEndian>(gps_time)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "gps_time".to_string()))
                }
            }
        }
        if self.header.point_data_format.has_color() {
            match point.red {
                Some(red) => try!(writer.write_u16::<LittleEndian>(red)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "red".to_string()))
                }
            }
            match point.green {
                Some(green) => try!(writer.write_u16::<LittleEndian>(green)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "green".to_string()))
                }
            }
            match point.blue {
                Some(blue) => try!(writer.write_u16::<LittleEndian>(blue)),
                None => {
                    return Err(Error::PointFormat(self.header.point_data_format,
                                                     "blue".to_string()))
                }
            }
        }
        match point.extra_bytes {
            Some(ref bytes) => try!(writer.write_all(&bytes[..])),
            None => {}
        }
        Ok(())
    }
}

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

    use std::fs::remove_file;
    use std::io::Cursor;
    use std::path::Path;

    use point::Point;

    fn roundtrip<P: AsRef<Path>>(path: P) {
        let mut lasfile = File::from_path(path).unwrap();
        let ref mut cursor = Cursor::new(Vec::new());
        lasfile.write_to(cursor).unwrap();
        cursor.set_position(0);
        let lasfile2 = File::read_from(cursor).unwrap();
        assert_eq!(lasfile, lasfile2);
    }

    #[test]
    fn roundtrip_1_0_0() {
        roundtrip("data/1.0_0.las");
    }

    #[test]
    fn roundtrip_1_0_1() {
        roundtrip("data/1.0_1.las");
    }

    #[test]
    fn roundtrip_1_1_0() {
        roundtrip("data/1.1_0.las");
    }

    #[test]
    fn roundtrip_1_1_1() {
        roundtrip("data/1.1_1.las");
    }

    #[test]
    fn roundtrip_1_2_0() {
        roundtrip("data/1.2_0.las");
    }

    #[test]
    fn roundtrip_1_2_1() {
        roundtrip("data/1.2_1.las");
    }

    #[test]
    fn roundtrip_1_2_2() {
        roundtrip("data/1.2_2.las");
    }

    #[test]
    fn roundtrip_1_2_3() {
        roundtrip("data/1.2_3.las");
    }

    /// This file is good as it exercieses a weird use case, but the test fails at the moment. I'm
    /// not sure why, so I'm going to keep it around but ignore it.
    #[test]
    #[ignore]
    fn roundtrip_extrabytes() {
        roundtrip("data/extrabytes.las");
    }

    #[test]
    fn point_format_1_has_gps_time() {
        let lasfile = File::from_path("data/1.0_1.las").unwrap();
        let ref point = lasfile.points()[0];
        assert!(point.gps_time.is_some());
    }

    #[test]
    fn point_format_2_has_color() {
        let lasfile = File::from_path("data/1.2_2.las").unwrap();
        let ref point = lasfile.points()[0];
        assert!(point.red.is_some());
        assert!(point.green.is_some());
        assert!(point.blue.is_some());
    }

    #[test]
    fn write_one_point() {
        let mut point = Point::new();
        point.x = 1.0;
        point.y = 2.0;
        point.z = 3.0;
        let mut lasfile = File::new();
        lasfile.add_point(point);
        lasfile.to_path("temp.las").unwrap();

        let lasfile = File::from_path("temp.las").unwrap();
        let ref point = lasfile.points()[0];
        assert_eq!(1.0, point.x);
        assert_eq!(2.0, point.y);
        assert_eq!(3.0, point.z);

        remove_file("temp.las").unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate sdl2_ttf;

use std::ops::Index;
use std::cmp::Ordering;
use std::path::Path;

pub const OUTLINE_WIDTH : u16 = 2 ;

pub struct FontSet {
    /// size of the loaded font
    font_size: u16,
    /// width of a single character withotu outline
    char_dimensions: (u8,u8),
    /// Font object without outline
    font_regular: sdl2_ttf::Font,
    /// Font object with outline
    font_bold: sdl2_ttf::Font,
}

impl Eq for FontSet {}

impl PartialEq for FontSet {
    fn eq(&self, other: &Self) -> bool {
        self.font_size.eq(&other.font_size)
    }
}

impl PartialOrd for FontSet {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.font_size.partial_cmp(&other.font_size)
    }
}

impl Ord for FontSet {
    fn cmp(&self, other: &Self) -> Ordering {
        self.font_size.cmp(&other.font_size)
    }
}

impl Index<usize> for FontList {
    type Output = FontSet;
    fn index(&self, index: usize) -> &FontSet {
        &self.get_font_set(index).unwrap()
    }
}

impl FontSet {
    pub fn get_size(&self) -> u16 {
        self.font_size
    }
    pub fn get_regular_font(&self) -> &sdl2_ttf::Font {
        &self.font_regular
    }
    pub fn get_outline_font(&self) -> &sdl2_ttf::Font {
        &self.font_bold
    }
}

// MADE PUBLIC FOR TESTS, MAKE PRIVATE WHEN NOT NECESSARY ANYMORE
pub struct FontList {
    // font list is a SORTED font list
    fonts: Vec<FontSet>,
}

impl FontList {
    pub fn new(font_path: &Path, ttf_context: &sdl2_ttf::Sdl2TtfContext) -> Result<FontList, ()> {
        let mut result = FontList { fonts: Vec::<FontSet>::new() };
        let mut font_size = 3;
        let font_size_max = 128;
        let font_size_increment = 1;
        let mut error: bool = false;
        'fontlist: while (font_size < font_size_max) {
            let mut font_bold;
            let font_regular = ttf_context.load_font(font_path, font_size)
                .expect("Unable to load font");
            let char_dimensions = font_regular.size_of_char('A').expect("Failed to get size of char");
            let char_dimensions = (char_dimensions.0 as u8,char_dimensions.0 as u8);
            match ttf_context.load_font(font_path, font_size) {
                Ok(font_set) => {
                    font_bold = font_set;
                }
                Err(_) => {
                    error = true;
                    break 'fontlist;
                }
            }
            font_bold.set_outline_width(OUTLINE_WIDTH);
            result.fonts.push(FontSet {
                font_size: font_size,
                char_dimensions: char_dimensions,
                font_regular: font_regular,
                font_bold: font_bold,
            });
            font_size += font_size_increment;
        }
        if error {
            Err(())
        } else {
            Ok(result)
        }
    }

    pub fn get_font_set(&self, index: usize) -> Option<&FontSet> {
        self.fonts.get(index)
    }

    pub fn add_font_set(&mut self, font_set: FontSet) -> Result<(), &FontSet> {
        let result = self.fonts
                         .binary_search_by(|fontset| fontset.font_size.cmp(&font_set.font_size));
        match result {
            Ok(index) => Err(self.fonts.get(index).unwrap()),
            Err(index) => {
                self.fonts.insert(index, font_set);
                Ok(())
            }
        }
    }

    /// Given a font size, get the closest from the fontlist
    pub fn get_closest_font_set(&self, font_size: u16) -> Result<&FontSet, ()> {
        match self.fonts.len() {
            0 => Err(()),
            1 => Ok(self.fonts.first().unwrap()),
            _ => {
                let search_result = self.fonts.binary_search_by(|fontset| {
                    fontset.font_size.cmp(&font_size)
                });
                match search_result {
                    Ok(index) => Ok(&self.fonts[index]),
                    Err(0) => Ok(&self.fonts[0]),
                    Err(index) if index == self.fonts.len() => Ok(&self.fonts.last().unwrap()),
                    Err(index) => {
                        let font_set_min = &self.fonts[index - 1];
                        let font_set_max = &self.fonts[index];
                        if (font_set_max.font_size - font_size >
                            font_size - font_set_min.font_size) {
                            Ok(font_set_min)
                        } else {
                            Ok(font_set_max)
                        }
                    }
                }
            }
        }
    }

    /// Given a string and a maximum width, get the fittest font from the FontList
    pub fn get_fittest_font_set(&self, string:&str,max_dims:(Option<u32>,Option<u32>),outline:bool) -> Result<&FontSet, ()> {
        if max_dims == (None,None) {
            Err(()) // cant get the fittiest if both are None !
        } else {
            match self.fonts.len() {
                0 => Err(()),
                1 => Ok(self.fonts.first().unwrap()),
                _ => {
                    let search_result = self.fonts.binary_search_by(|fontset| {
                        let ref font_bold = fontset.font_bold;
                        let ref font_regular = fontset.font_regular;
                        let string_dims =
                            if outline {font_bold} else {font_regular}
                            .size_of(string)
                            .expect("Failed to get size of some string");
                        match max_dims {
                            (Some(width),Some(height)) => {
                                match (string_dims.0.cmp(&width),string_dims.1.cmp(&height)) {
                                    (Ordering::Greater,_) | (_,Ordering::Greater) => Ordering::Greater,
                                    (Ordering::Equal,_) | (_,Ordering::Equal) => Ordering::Equal,
                                    _ => Ordering::Less
                                }
                            },
                            (Some(width),None) => {
                                string_dims.0.cmp(&width)
                            },
                            (None,Some(height)) => {
                                string_dims.1.cmp(&height)
                            },
                            (None,None) => unreachable!()
                        }
                    });
                    match search_result {
                        Ok(index) => Ok(&self.fonts[index]),
                        Err(0) => Ok(&self.fonts[0]),
                        Err(index) if index == self.fonts.len() => Ok(&self.fonts.last().unwrap()),
                        Err(index) => Ok(&self.fonts[index - 1])
                        // it should fit, meaning that if we can't find something exactly we should
                        // take the first that fits
                    }
                }
            }
        }
    }
}
<commit_msg>Remove font:get_closest_font_set<commit_after>extern crate sdl2_ttf;

use std::ops::Index;
use std::cmp::Ordering;
use std::path::Path;

pub const OUTLINE_WIDTH : u16 = 2 ;

pub struct FontSet {
    /// size of the loaded font
    font_size: u16,
    /// width of a single character withotu outline
    char_dimensions: (u8,u8),
    /// Font object without outline
    font_regular: sdl2_ttf::Font,
    /// Font object with outline
    font_bold: sdl2_ttf::Font,
}

impl Eq for FontSet {}

impl PartialEq for FontSet {
    fn eq(&self, other: &Self) -> bool {
        self.font_size.eq(&other.font_size)
    }
}

impl PartialOrd for FontSet {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.font_size.partial_cmp(&other.font_size)
    }
}

impl Ord for FontSet {
    fn cmp(&self, other: &Self) -> Ordering {
        self.font_size.cmp(&other.font_size)
    }
}

impl Index<usize> for FontList {
    type Output = FontSet;
    fn index(&self, index: usize) -> &FontSet {
        &self.get_font_set(index).unwrap()
    }
}

impl FontSet {
    pub fn get_size(&self) -> u16 {
        self.font_size
    }
    pub fn get_regular_font(&self) -> &sdl2_ttf::Font {
        &self.font_regular
    }
    pub fn get_outline_font(&self) -> &sdl2_ttf::Font {
        &self.font_bold
    }
}

// MADE PUBLIC FOR TESTS, MAKE PRIVATE WHEN NOT NECESSARY ANYMORE
pub struct FontList {
    // font list is a SORTED font list
    fonts: Vec<FontSet>,
}

impl FontList {
    pub fn new(font_path: &Path, ttf_context: &sdl2_ttf::Sdl2TtfContext) -> Result<FontList, ()> {
        let mut result = FontList { fonts: Vec::<FontSet>::new() };
        let mut font_size = 3;
        let font_size_max = 128;
        let font_size_increment = 1;
        let mut error: bool = false;
        'fontlist: while (font_size < font_size_max) {
            let mut font_bold;
            let font_regular = ttf_context.load_font(font_path, font_size)
                .expect("Unable to load font");
            let char_dimensions = font_regular.size_of_char('A').expect("Failed to get size of char");
            let char_dimensions = (char_dimensions.0 as u8,char_dimensions.0 as u8);
            match ttf_context.load_font(font_path, font_size) {
                Ok(font_set) => {
                    font_bold = font_set;
                }
                Err(_) => {
                    error = true;
                    break 'fontlist;
                }
            }
            font_bold.set_outline_width(OUTLINE_WIDTH);
            result.fonts.push(FontSet {
                font_size: font_size,
                char_dimensions: char_dimensions,
                font_regular: font_regular,
                font_bold: font_bold,
            });
            font_size += font_size_increment;
        }
        if error {
            Err(())
        } else {
            Ok(result)
        }
    }

    pub fn get_font_set(&self, index: usize) -> Option<&FontSet> {
        self.fonts.get(index)
    }

    pub fn add_font_set(&mut self, font_set: FontSet) -> Result<(), &FontSet> {
        let result = self.fonts
                         .binary_search_by(|fontset| fontset.font_size.cmp(&font_set.font_size));
        match result {
            Ok(index) => Err(self.fonts.get(index).unwrap()),
            Err(index) => {
                self.fonts.insert(index, font_set);
                Ok(())
            }
        }
    }

    /// Given a string and a maximum width, get the fittest font from the FontList
    pub fn get_fittest_font_set(&self, string:&str,max_dims:(Option<u32>,Option<u32>),outline:bool) -> Result<&FontSet, ()> {
        if max_dims == (None,None) {
            Err(()) // cant get the fittiest if both are None !
        } else {
            match self.fonts.len() {
                0 => Err(()),
                1 => Ok(self.fonts.first().unwrap()),
                _ => {
                    let search_result = self.fonts.binary_search_by(|fontset| {
                        let ref font_bold = fontset.font_bold;
                        let ref font_regular = fontset.font_regular;
                        let string_dims =
                            if outline {font_bold} else {font_regular}
                            .size_of(string)
                            .expect("Failed to get size of some string");
                        match max_dims {
                            (Some(width),Some(height)) => {
                                match (string_dims.0.cmp(&width),string_dims.1.cmp(&height)) {
                                    (Ordering::Greater,_) | (_,Ordering::Greater) => Ordering::Greater,
                                    (Ordering::Equal,_) | (_,Ordering::Equal) => Ordering::Equal,
                                    _ => Ordering::Less
                                }
                            },
                            (Some(width),None) => {
                                string_dims.0.cmp(&width)
                            },
                            (None,Some(height)) => {
                                string_dims.1.cmp(&height)
                            },
                            (None,None) => unreachable!()
                        }
                    });
                    match search_result {
                        Ok(index) => Ok(&self.fonts[index]),
                        Err(0) => Ok(&self.fonts[0]),
                        Err(index) if index == self.fonts.len() => Ok(&self.fonts.last().unwrap()),
                        Err(index) => Ok(&self.fonts[index - 1])
                        // it should fit, meaning that if we can't find something exactly we should
                        // take the first that fits
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// This file contains various trait resolution methods used by codegen.
// They all assume regions can be erased and monomorphic types.  It
// seems likely that they should eventually be merged into more
// general routines.

use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::{
    FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
    Unimplemented,
};
use rustc_errors::ErrorReported;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};

/// Attempts to resolve an obligation to a `ImplSource`. The result is
/// a shallow `ImplSource` resolution, meaning that we do not
/// (necessarily) resolve all nested obligations on the impl. Note
/// that type check should guarantee to us that all nested
/// obligations *could be* resolved if we wanted to.
/// Assumes that this is run after the entire crate has been successfully type-checked.
pub fn codegen_fulfill_obligation<'tcx>(
    ty: TyCtxt<'tcx>,
    (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
    // Remove any references to regions; this helps improve caching.
    let trait_ref = ty.erase_regions(&trait_ref);

    debug!(
        "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
        (param_env, trait_ref),
        trait_ref.def_id()
    );

    // Do the initial selection for the obligation. This yields the
    // shallow result we are looking for -- that is, what specific impl.
    ty.infer_ctxt().enter(|infcx| {
        let mut selcx = SelectionContext::new(&infcx);

        let obligation_cause = ObligationCause::dummy();
        let obligation =
            Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());

        let selection = match selcx.select(&obligation) {
            Ok(Some(selection)) => selection,
            Ok(None) => {
                // Ambiguity can happen when monomorphizing during trans
                // expands to some humongo type that never occurred
                // statically -- this humongo type can then overflow,
                // leading to an ambiguous result. So report this as an
                // overflow bug, since I believe this is the only case
                // where ambiguity can result.
                infcx.tcx.sess.delay_span_bug(
                    rustc_span::DUMMY_SP,
                    &format!(
                        "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
                         overflow or prior type error",
                        trait_ref
                    ),
                );
                return Err(ErrorReported);
            }
            Err(Unimplemented) => {
                // This can trigger when we probe for the source of a `'static` lifetime requirement
                // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
                infcx.tcx.sess.delay_span_bug(
                    rustc_span::DUMMY_SP,
                    &format!(
                        "Encountered error `Unimplemented` selecting `{:?}` during codegen",
                        trait_ref
                    ),
                );
                return Err(ErrorReported);
            }
            Err(e) => {
                bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
            }
        };

        debug!("fulfill_obligation: selection={:?}", selection);

        // Currently, we use a fulfillment context to completely resolve
        // all nested obligations. This is because they can inform the
        // inference of the impl's type parameters.
        let mut fulfill_cx = FulfillmentContext::new();
        let impl_source = selection.map(|predicate| {
            debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
            fulfill_cx.register_predicate_obligation(&infcx, predicate);
        });
        let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source);

        info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
        Ok(impl_source)
    })
}

// # Global Cache

/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
/// for use after type-check has completed, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
fn drain_fulfillment_cx_or_panic<T>(
    infcx: &InferCtxt<'_, 'tcx>,
    fulfill_cx: &mut FulfillmentContext<'tcx>,
    result: &T,
) -> T
where
    T: TypeFoldable<'tcx>,
{
    debug!("drain_fulfillment_cx_or_panic()");

    // In principle, we only need to do this so long as `result`
    // contains unbound type parameters. It could be a slight
    // optimization to stop iterating early.
    if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
        bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
    }

    let result = infcx.resolve_vars_if_possible(result);
    infcx.tcx.erase_regions(&result)
}
<commit_msg>normalize in codegen_fulfill_obligations<commit_after>// This file contains various trait resolution methods used by codegen.
// They all assume regions can be erased and monomorphic types.  It
// seems likely that they should eventually be merged into more
// general routines.

use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::{
    FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
    Unimplemented,
};
use rustc_errors::ErrorReported;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};

/// Attempts to resolve an obligation to a `ImplSource`. The result is
/// a shallow `ImplSource` resolution, meaning that we do not
/// (necessarily) resolve all nested obligations on the impl. Note
/// that type check should guarantee to us that all nested
/// obligations *could be* resolved if we wanted to.
/// Assumes that this is run after the entire crate has been successfully type-checked.
pub fn codegen_fulfill_obligation<'tcx>(
    tcx: TyCtxt<'tcx>,
    (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
    // Remove any references to regions and normalize; this helps improve caching.
    let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);

    debug!(
        "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
        (param_env, trait_ref),
        trait_ref.def_id()
    );

    // Do the initial selection for the obligation. This yields the
    // shallow result we are looking for -- that is, what specific impl.
    tcx.infer_ctxt().enter(|infcx| {
        let mut selcx = SelectionContext::new(&infcx);

        let obligation_cause = ObligationCause::dummy();
        let obligation =
            Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());

        let selection = match selcx.select(&obligation) {
            Ok(Some(selection)) => selection,
            Ok(None) => {
                // Ambiguity can happen when monomorphizing during trans
                // expands to some humongo type that never occurred
                // statically -- this humongo type can then overflow,
                // leading to an ambiguous result. So report this as an
                // overflow bug, since I believe this is the only case
                // where ambiguity can result.
                infcx.tcx.sess.delay_span_bug(
                    rustc_span::DUMMY_SP,
                    &format!(
                        "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
                         overflow or prior type error",
                        trait_ref
                    ),
                );
                return Err(ErrorReported);
            }
            Err(Unimplemented) => {
                // This can trigger when we probe for the source of a `'static` lifetime requirement
                // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
                infcx.tcx.sess.delay_span_bug(
                    rustc_span::DUMMY_SP,
                    &format!(
                        "Encountered error `Unimplemented` selecting `{:?}` during codegen",
                        trait_ref
                    ),
                );
                return Err(ErrorReported);
            }
            Err(e) => {
                bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
            }
        };

        debug!("fulfill_obligation: selection={:?}", selection);

        // Currently, we use a fulfillment context to completely resolve
        // all nested obligations. This is because they can inform the
        // inference of the impl's type parameters.
        let mut fulfill_cx = FulfillmentContext::new();
        let impl_source = selection.map(|predicate| {
            debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
            fulfill_cx.register_predicate_obligation(&infcx, predicate);
        });
        let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source);

        info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
        Ok(impl_source)
    })
}

// # Global Cache

/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
/// for use after type-check has completed, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
fn drain_fulfillment_cx_or_panic<T>(
    infcx: &InferCtxt<'_, 'tcx>,
    fulfill_cx: &mut FulfillmentContext<'tcx>,
    result: &T,
) -> T
where
    T: TypeFoldable<'tcx>,
{
    debug!("drain_fulfillment_cx_or_panic()");

    // In principle, we only need to do this so long as `result`
    // contains unbound type parameters. It could be a slight
    // optimization to stop iterating early.
    if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
        bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
    }

    let result = infcx.resolve_vars_if_possible(result);
    infcx.tcx.erase_regions(&result)
}
<|endoftext|>


<commit_before>use nalgebra::{self, Point3};
use num::Float;
use num::traits::FloatConst;
use std::iter::Peekable;
use std::ops::Range;
use std::marker::PhantomData;

use super::generate::{Conjoint, Indexed};
use super::primitive::{Polygon, Triangle, Quad};

pub struct UVSphere<T>
    where T: Float + FloatConst
{
    nu: usize,
    nv: usize,
    us: Range<usize>, // meridians
    vs: Peekable<Range<usize>>, // parallels
    phantom_t: PhantomData<T>,
}

impl<T> UVSphere<T>
    where T: Float + FloatConst
{
    pub fn with_unit_radius(nu: usize, nv: usize) -> Self {
        let nu = nalgebra::max(3, nu);
        let nv = nalgebra::max(3, nv);
        UVSphere {
            nu: nu,
            nv: nv,
            us: 0..nu,
            vs: (0..nv).peekable(),
            phantom_t: PhantomData,
        }
    }

    fn point(&self, u: usize, v: usize) -> Point3<T> {
        point(u, v, self.nu, self.nv)
    }

    fn indexed_point(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }
}

impl<T> Conjoint<Point3<T>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn conjoint_point(&self, index: usize) -> Point3<T> {
        if index == 0 {
            self.point(0, 0)
        }
        else if index == self.conjoint_point_count() - 1 {
            self.point(0, self.nv)
        }
        else {
            let index = index - 1;
            self.point(index % self.nu, (index / self.nv) + 1)
        }
    }

    fn conjoint_point_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<T> Indexed<Polygon<usize>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn indexed_polygon(&self, index: usize) -> Polygon<usize> {
        let u = index % self.nu;
        let v = index / self.nu;
        if v == 0 {
            Polygon::Triangle(Triangle::new(self.indexed_point(u, v),
                                            self.indexed_point(u, v + 1),
                                            self.indexed_point(u + 1, v + 1)))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(self.indexed_point(u + 1, v + 1),
                                            self.indexed_point(u + 1, v),
                                            self.indexed_point(u, v)))
        }
        else {
            Polygon::Quad(Quad::new(self.indexed_point(u, v),
                                    self.indexed_point(u, v + 1),
                                    self.indexed_point(u + 1, v + 1),
                                    self.indexed_point(u + 1, v)))
        }
    }

    fn indexed_polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<T> Iterator for UVSphere<T>
    where T: Float + FloatConst
{
    type Item = Polygon<Point3<T>>;

    fn next(&mut self) -> Option<Self::Item> {
        let nu = self.nu;
        let nv = self.nv;

        // Iterate over meridians (`self.us`). When meridians are exhausted,
        // reset the iteration and advance iteration over parallels (`self.vs`).
        // Continue until parallels are exhausted.
        let u = match self.us.next() {
            Some(u) => u,
            None => {
                self.vs.next();
                self.us = 1..nu;
                0
            },
        };
        self.vs.peek().map(|v| {
            let v = *v;

            // Generate the points at the current meridian and parallel.
            let a = point(u, v, nu, nv);
            let b = point(u, v + 1, nu, nv);
            let c = point(u + 1, v + 1, nu, nv);
            let d = point(u + 1, v, nu, nv);

            // Emit triangles at the poles, otherwise quads.
            if v == 0 {
                Polygon::Triangle(Triangle::new(a, b, c))
            }
            else if v == nv - 1 {
                Polygon::Triangle(Triangle::new(c, d, a))
            }
            else {
                Polygon::Quad(Quad::new(a, b, c, d))
            }
        })
    }
}

fn point<T>(u: usize, v: usize, nu: usize, nv: usize) -> Point3<T>
    where T: Float + FloatConst
{
    let u = (T::from(u).unwrap() / T::from(nu).unwrap()) * T::PI() * (T::one() + T::one());
    let v = (T::from(v).unwrap() / T::from(nv).unwrap()) * T::PI();
    Point3::new(u.cos() * v.sin(), u.sin() * v.sin(), v.cos())
}
<commit_msg>Avoid generating spurious points in `UVSphere`.<commit_after>use nalgebra::{self, Point3};
use num::Float;
use num::traits::FloatConst;
use std::iter::Peekable;
use std::ops::Range;
use std::marker::PhantomData;

use super::generate::{Conjoint, Indexed};
use super::primitive::{Polygon, Triangle, Quad};

pub struct UVSphere<T>
    where T: Float + FloatConst
{
    nu: usize,
    nv: usize,
    us: Range<usize>, // meridians
    vs: Peekable<Range<usize>>, // parallels
    phantom_t: PhantomData<T>,
}

impl<T> UVSphere<T>
    where T: Float + FloatConst
{
    pub fn with_unit_radius(nu: usize, nv: usize) -> Self {
        let nu = nalgebra::max(3, nu);
        let nv = nalgebra::max(3, nv);
        UVSphere {
            nu: nu,
            nv: nv,
            us: 0..nu,
            vs: (0..nv).peekable(),
            phantom_t: PhantomData,
        }
    }

    fn point(&self, u: usize, v: usize) -> Point3<T> {
        point(u, v, self.nu, self.nv)
    }

    fn indexed_point(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }
}

impl<T> Conjoint<Point3<T>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn conjoint_point(&self, index: usize) -> Point3<T> {
        if index == 0 {
            self.point(0, 0)
        }
        else if index == self.conjoint_point_count() - 1 {
            self.point(0, self.nv)
        }
        else {
            let index = index - 1;
            self.point(index % self.nu, (index / self.nv) + 1)
        }
    }

    fn conjoint_point_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<T> Indexed<Polygon<usize>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn indexed_polygon(&self, index: usize) -> Polygon<usize> {
        let u = index % self.nu;
        let v = index / self.nu;

        let lower = self.indexed_point(u, v);
        let upper = self.indexed_point(u + 1, v + 1);
        if v == 0 {
            Polygon::Triangle(Triangle::new(lower, self.indexed_point(u, v + 1), upper))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(upper, self.indexed_point(u + 1, v), lower))
        }
        else {
            Polygon::Quad(Quad::new(lower,
                                    self.indexed_point(u, v + 1),
                                    upper,
                                    self.indexed_point(u + 1, v)))
        }
    }

    fn indexed_polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<T> Iterator for UVSphere<T>
    where T: Float + FloatConst
{
    type Item = Polygon<Point3<T>>;

    fn next(&mut self) -> Option<Self::Item> {
        let nu = self.nu;
        let nv = self.nv;

        // Iterate over meridians (`self.us`). When meridians are exhausted,
        // reset the iteration and advance iteration over parallels (`self.vs`).
        // Continue until parallels are exhausted.
        let u = match self.us.next() {
            Some(u) => u,
            None => {
                self.vs.next();
                self.us = 1..nu;
                0
            },
        };
        self.vs.peek().map(|v| {
            let v = *v;

            // Generate the points at the current meridian and parallel. The
            // upper and lower bounds of (u, v) are always used, so Generate
            // them in advance. Emit triangles at the poles, otherwise quads.
            let lower = point(u, v, nu, nv);
            let upper = point(u + 1, v + 1, nu, nv);
            if v == 0 {
                Polygon::Triangle(Triangle::new(lower, point(u, v + 1, nu, nv), upper))
            }
            else if v == nv - 1 {
                Polygon::Triangle(Triangle::new(upper, point(u + 1, v, nu, nv), lower))
            }
            else {
                Polygon::Quad(Quad::new(lower,
                                        point(u, v + 1, nu, nv),
                                        upper,
                                        point(u + 1, v, nu, nv)))
            }
        })
    }
}

fn point<T>(u: usize, v: usize, nu: usize, nv: usize) -> Point3<T>
    where T: Float + FloatConst
{
    let u = (T::from(u).unwrap() / T::from(nu).unwrap()) * T::PI() * (T::one() + T::one());
    let v = (T::from(v).unwrap() / T::from(nv).unwrap()) * T::PI();
    Point3::new(u.cos() * v.sin(), u.sin() * v.sin(), v.cos())
}
<|endoftext|>


<commit_before>extern crate rand;

use types::*;

pub fn new_actions() -> Vec<Action> {
    let actions: Vec<Action> = Vec::new();
    actions
}

pub fn new_game() -> Game {
    let all_tiles = (0..TILES).map(|i| {
        let row = i / COLS;
        let col = i % ROWS;
        if let Some(tile) = Tile::new(row, col) {
            tile
        } else {
            panic!("Attempted to create invalid tile ({},{})", row, col)
        }
        }).collect();
    let (starting_tiles, remaining_tiles) = choose_tiles(all_tiles, PLAYERS);
    let players = new_players(remaining_tiles);
    let slots = initial_slots(starting_tiles);
    Game {
        board: Board { slots: slots },
        players: players,
        turn: PlayerId::One,
        merge_decision: None
    }
}

fn choose_tiles(tiles: Vec<Tile>, count: u8) -> (Vec<Tile>, Vec<Tile>) {
    let mut remaining_tiles = tiles;
    let mut random_tiles = Vec::new();
    for _ in 0..count {
        let random_index = rand::random::<usize>() % remaining_tiles.len();
        random_tiles.push(remaining_tiles.remove(random_index));
    }
    (random_tiles, remaining_tiles)
}

fn new_players(tiles: Vec<Tile>) -> Vec<Player>{
    let init_players: Vec<Player> = Vec::new();
    let (players, _) = (0..PLAYERS)
        .fold( (init_players, tiles), | (mut v, remaining), i | {
            let (player_tiles, new_remaining) = choose_tiles(remaining, 6);
            let player = new_player(PlayerId::new(i+1).unwrap(), player_tiles);
            v.push(player);
            (v, new_remaining)
        });
    players
}

pub fn new_player(id: PlayerId, tiles: Vec<Tile>) -> Player {
    Player { id: id, money: 6000, shares: empty_shares(), tiles: tiles }
}

fn empty_shares() -> PlayerShares {
    PlayerShares { luxor: 0, tower: 0, american: 0, festival: 0, worldwide: 0, continental: 0, imperial: 0 }
}

pub fn initial_slots(starting_tiles: Vec<Tile>) -> Vec<Slot> {
    (0..ROWS).flat_map(|row| -> Vec<Slot> {
        (0..COLS).map(|col| {
            Slot {
                row: row,
                col: col,
                hotel: None,
                has_tile: has_tile_on_slot(&starting_tiles, row, col)
            }
        }).collect()
    }).collect()
}

fn has_tile_on_slot(tiles: & Vec<Tile>, row: u8, col: u8) -> bool {
    tiles.iter().any(|t| t.row() == row && t.col() == col)
}

pub fn compute_state(last_state: &Game, actions: &Vec<Action>) -> Game {
    let mut state = Game {
        board: last_state.board.clone(),
        players: last_state.players.clone(),
        turn: last_state.turn.clone(),
        merge_decision: last_state.merge_decision.clone()
    };
    for action in actions {
    }
    state
}

pub fn play_turn(game: &Game, action: Action) -> Game {
    match action {
        Action::PlaceTile { player, tile } => {
            place_tile(game, player, &tile)
        }
        _ => panic!(format!("I don't know how to play a turn with action {:?}", action))
    }
}

fn place_tile(game: &Game, player: PlayerId, tile: &Tile) -> Game {
    Game {
        board: place_tile_on_board(&game.board, &tile),
        players: game.players.clone(),
        turn: game.turn.clone(),
        merge_decision: game.merge_decision.clone()
    }
}

fn place_tile_on_board(board: &Board, tile: &Tile) -> Board {
    let slots = board.slots
        .iter()
        .map(|s| {
            if s.row == tile.row() && s.col == tile.col() {
                Slot { row: s.row, col: s.col, has_tile: true, hotel: s.hotel.clone() }
            } else {
                s.clone()
            }
        })
        .collect();
    Board { slots: slots }
}

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

    type BoardTiles = [[i32; COLS as usize]; ROWS as usize];
    type PlayerTiles = [[(i32,i32); 6]; PLAYERS as usize];

    #[test]
    fn players_start_with_six_tiles() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.tiles.len(), 6);
        }
    }

    #[test]
    fn players_start_with_6000_in_cash() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.money, 6000);
        }
    }

    #[test]
    fn players_start_with_zero_shares() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.shares.luxor, 0);
            assert_eq!(player.shares.tower, 0);
            assert_eq!(player.shares.american, 0);
            assert_eq!(player.shares.festival, 0);
            assert_eq!(player.shares.worldwide, 0);
            assert_eq!(player.shares.continental, 0);
            assert_eq!(player.shares.imperial, 0);
        }
    }

    #[test]
    fn game_starts_with_four_placed_tiles() {
        let game = new_game();
        let board_tiles = game.board.slots.iter().filter(|s| s.has_tile).count();
        assert_eq!(board_tiles, 4)
    }

    #[test]
    fn placing_a_tile_adds_tile_to_board() {
        let start_tiles = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let end_tiles =   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let player_tiles = [[ (0,0), (0,1), (0,2), (0,3), (0,4), (0,5) ],
                            [ (1,0), (1,1), (1,2), (1,3), (1,4), (1,5) ],
                            [ (2,2), (2,1), (2,2), (2,3), (2,4), (2,5) ],
                            [ (3,3), (3,1), (3,2), (3,3), (3,4), (3,5) ]];
        let game = new_game_with_tiles(start_tiles, player_tiles);
        let tile_to_place = Tile::new(5,11).unwrap();
        let action = Action::PlaceTile { player: PlayerId::One, tile: tile_to_place };
        let game_after = play_turn(&game, action);
        assert_boards_equal(&tiles_to_board(&end_tiles), &game_after.board);
    }

    fn new_game_with_tiles(start_tiles: BoardTiles, player_tiles: PlayerTiles) -> Game {
        let (starting_tiles, remaining) = board_tiles_to_tiles(&start_tiles);
        let players = player_tiles
            .iter()
            .enumerate()
            .map(|(i, tiles)| {
                let _tiles = tiles
                    .iter()
                    .map(|&(r,c)| Tile::new(r as u8, c as u8).unwrap() )
                    .collect();
                new_player(PlayerId::new((i+1) as u8).unwrap(), _tiles)
            })
            .collect();
        let slots = initial_slots(starting_tiles);
        Game {
            board: Board { slots: slots },
            players: players,
            turn: PlayerId::One,
            merge_decision: None
        }
    }

    fn board_tiles_to_tiles(tiles: &BoardTiles) -> (Vec<Tile>, Vec<Tile>) {
        let mut chosen = Vec::new();
        let mut others = Vec::new();
        for row in 0..tiles.len() {
            for col in 0..tiles[0].len() {
                let tile = Tile::new(row as u8, col as u8).unwrap();
                if tiles[row][col] == 1 {
                    chosen.push(tile)
                } else {
                    others.push(tile)
                }
            }
        }
        (chosen, others)
    }

    fn assert_boards_equal(expected: &Board, actual: &Board) {
        let are_equal = expected.slots
            .iter()
            .zip(actual.slots.iter())
            .all(|(left, right)| *left == *right );
        let error_msg = format!("\n\nBoard did not have expected tiles.\n\nExpected tiles:\n{}\n\nActual tiles:\n{}\n\n", print_board(&expected), print_board(&actual));
        assert!(are_equal, error_msg);
    }

    fn tiles_to_board(tiles: &BoardTiles) -> Board {
        let board_tiles = tiles
            .iter()
            .enumerate()
            .flat_map(|(row, row_tiles)| {
                let slots: Vec<Slot> = row_tiles
                    .iter()
                    .enumerate()
                    .map(|(col, val): (usize, &i32)| {
                        let has_tile = *val == 1;
                        Slot { row: row as u8, col: col as u8, has_tile: has_tile, hotel: None }
                    })
                    .collect();
                slots
            }).collect();
        Board { slots: board_tiles }
    }

    fn row_to_char<'a>(row: u8) -> &'a str {
        let mapping = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
        mapping[row as usize]
    }

    fn print_tile(slot: &Slot) -> String{
        format!("{}{}", row_to_char(slot.row), slot.col + 1)
    }

    fn print_board(board: &Board) -> String {
        let mut string = String::new();
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12\n");
        for row in board.slots.chunks(COLS as usize) {
            let row_char = row_to_char(row[0].row);
            string.push_str(&format!("{}  ", row_char));
            for slot in row {
                string.push_str(&format!("{:<2} ", if slot.has_tile { '\u{25FC}' } else { '\u{25FB}' }));
            }
            string.push_str(&format!("{}\n", row_char));
        }
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12");
        string
    }
}
<commit_msg>Properly run through actions to update state<commit_after>extern crate rand;

use types::*;

pub fn new_actions() -> Vec<Action> {
    let actions: Vec<Action> = Vec::new();
    actions
}

pub fn new_game() -> Game {
    let all_tiles = (0..TILES).map(|i| {
        let row = i / COLS;
        let col = i % ROWS;
        if let Some(tile) = Tile::new(row, col) {
            tile
        } else {
            panic!("Attempted to create invalid tile ({},{})", row, col)
        }
        }).collect();
    let (starting_tiles, remaining_tiles) = choose_tiles(all_tiles, PLAYERS);
    let players = new_players(remaining_tiles);
    let slots = initial_slots(starting_tiles);
    Game {
        board: Board { slots: slots },
        players: players,
        turn: PlayerId::One,
        merge_decision: None
    }
}

fn choose_tiles(tiles: Vec<Tile>, count: u8) -> (Vec<Tile>, Vec<Tile>) {
    let mut remaining_tiles = tiles;
    let mut random_tiles = Vec::new();
    for _ in 0..count {
        let random_index = rand::random::<usize>() % remaining_tiles.len();
        random_tiles.push(remaining_tiles.remove(random_index));
    }
    (random_tiles, remaining_tiles)
}

fn new_players(tiles: Vec<Tile>) -> Vec<Player>{
    let init_players: Vec<Player> = Vec::new();
    let (players, _) = (0..PLAYERS)
        .fold( (init_players, tiles), | (mut v, remaining), i | {
            let (player_tiles, new_remaining) = choose_tiles(remaining, 6);
            let player = new_player(PlayerId::new(i+1).unwrap(), player_tiles);
            v.push(player);
            (v, new_remaining)
        });
    players
}

pub fn new_player(id: PlayerId, tiles: Vec<Tile>) -> Player {
    Player { id: id, money: 6000, shares: empty_shares(), tiles: tiles }
}

fn empty_shares() -> PlayerShares {
    PlayerShares { luxor: 0, tower: 0, american: 0, festival: 0, worldwide: 0, continental: 0, imperial: 0 }
}

pub fn initial_slots(starting_tiles: Vec<Tile>) -> Vec<Slot> {
    (0..ROWS).flat_map(|row| -> Vec<Slot> {
        (0..COLS).map(|col| {
            Slot {
                row: row,
                col: col,
                hotel: None,
                has_tile: has_tile_on_slot(&starting_tiles, row, col)
            }
        }).collect()
    }).collect()
}

fn has_tile_on_slot(tiles: & Vec<Tile>, row: u8, col: u8) -> bool {
    tiles.iter().any(|t| t.row() == row && t.col() == col)
}

pub fn compute_state(last_state: &Game, actions: &Vec<Action>) -> Game {
    actions.iter().fold(last_state.clone(), |game, action| {
        play_turn(&game, action)
    })
}

pub fn play_turn(game: &Game, action: &Action) -> Game {
    match *action {
        Action::PlaceTile { ref player, ref tile } => {
            place_tile(game, player.clone(), tile)
        }
        _ => panic!(format!("I don't know how to play a turn with action {:?}", action))
    }
}

fn place_tile(game: &Game, player: PlayerId, tile: &Tile) -> Game {
    Game {
        board: place_tile_on_board(&game.board, &tile),
        players: game.players.clone(),
        turn: game.turn.clone(),
        merge_decision: game.merge_decision.clone()
    }
}

fn place_tile_on_board(board: &Board, tile: &Tile) -> Board {
    let slots = board.slots
        .iter()
        .map(|s| {
            if s.row == tile.row() && s.col == tile.col() {
                Slot { row: s.row, col: s.col, has_tile: true, hotel: s.hotel.clone() }
            } else {
                s.clone()
            }
        })
        .collect();
    Board { slots: slots }
}

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

    type BoardTiles = [[i32; COLS as usize]; ROWS as usize];
    type PlayerTiles = [[(i32,i32); 6]; PLAYERS as usize];

    #[test]
    fn players_start_with_six_tiles() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.tiles.len(), 6);
        }
    }

    #[test]
    fn players_start_with_6000_in_cash() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.money, 6000);
        }
    }

    #[test]
    fn players_start_with_zero_shares() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.shares.luxor, 0);
            assert_eq!(player.shares.tower, 0);
            assert_eq!(player.shares.american, 0);
            assert_eq!(player.shares.festival, 0);
            assert_eq!(player.shares.worldwide, 0);
            assert_eq!(player.shares.continental, 0);
            assert_eq!(player.shares.imperial, 0);
        }
    }

    #[test]
    fn game_starts_with_four_placed_tiles() {
        let game = new_game();
        let board_tiles = game.board.slots.iter().filter(|s| s.has_tile).count();
        assert_eq!(board_tiles, 4)
    }

    #[test]
    fn placing_a_tile_adds_tile_to_board() {
        let start_tiles = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let end_tiles =   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let player_tiles = [[ (0,0), (0,1), (0,2), (0,3), (0,4), (0,5) ],
                            [ (1,0), (1,1), (1,2), (1,3), (1,4), (1,5) ],
                            [ (2,2), (2,1), (2,2), (2,3), (2,4), (2,5) ],
                            [ (3,3), (3,1), (3,2), (3,3), (3,4), (3,5) ]];
        let game = new_game_with_tiles(start_tiles, player_tiles);
        let tile_to_place = Tile::new(5,11).unwrap();
        let action = Action::PlaceTile { player: PlayerId::One, tile: tile_to_place };
        let game_after = play_turn(&game, &action);
        assert_boards_equal(&tiles_to_board(&end_tiles), &game_after.board);
    }

    fn new_game_with_tiles(start_tiles: BoardTiles, player_tiles: PlayerTiles) -> Game {
        let (starting_tiles, remaining) = board_tiles_to_tiles(&start_tiles);
        let players = player_tiles
            .iter()
            .enumerate()
            .map(|(i, tiles)| {
                let _tiles = tiles
                    .iter()
                    .map(|&(r,c)| Tile::new(r as u8, c as u8).unwrap() )
                    .collect();
                new_player(PlayerId::new((i+1) as u8).unwrap(), _tiles)
            })
            .collect();
        let slots = initial_slots(starting_tiles);
        Game {
            board: Board { slots: slots },
            players: players,
            turn: PlayerId::One,
            merge_decision: None
        }
    }

    fn board_tiles_to_tiles(tiles: &BoardTiles) -> (Vec<Tile>, Vec<Tile>) {
        let mut chosen = Vec::new();
        let mut others = Vec::new();
        for row in 0..tiles.len() {
            for col in 0..tiles[0].len() {
                let tile = Tile::new(row as u8, col as u8).unwrap();
                if tiles[row][col] == 1 {
                    chosen.push(tile)
                } else {
                    others.push(tile)
                }
            }
        }
        (chosen, others)
    }

    fn assert_boards_equal(expected: &Board, actual: &Board) {
        let are_equal = expected.slots
            .iter()
            .zip(actual.slots.iter())
            .all(|(left, right)| *left == *right );
        let error_msg = format!("\n\nBoard did not have expected tiles.\n\nExpected tiles:\n{}\n\nActual tiles:\n{}\n\n", print_board(&expected), print_board(&actual));
        assert!(are_equal, error_msg);
    }

    fn tiles_to_board(tiles: &BoardTiles) -> Board {
        let board_tiles = tiles
            .iter()
            .enumerate()
            .flat_map(|(row, row_tiles)| {
                let slots: Vec<Slot> = row_tiles
                    .iter()
                    .enumerate()
                    .map(|(col, val): (usize, &i32)| {
                        let has_tile = *val == 1;
                        Slot { row: row as u8, col: col as u8, has_tile: has_tile, hotel: None }
                    })
                    .collect();
                slots
            }).collect();
        Board { slots: board_tiles }
    }

    fn row_to_char<'a>(row: u8) -> &'a str {
        let mapping = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
        mapping[row as usize]
    }

    fn print_tile(slot: &Slot) -> String{
        format!("{}{}", row_to_char(slot.row), slot.col + 1)
    }

    fn print_board(board: &Board) -> String {
        let mut string = String::new();
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12\n");
        for row in board.slots.chunks(COLS as usize) {
            let row_char = row_to_char(row[0].row);
            string.push_str(&format!("{}  ", row_char));
            for slot in row {
                string.push_str(&format!("{:<2} ", if slot.has_tile { '\u{25FC}' } else { '\u{25FB}' }));
            }
            string.push_str(&format!("{}\n", row_char));
        }
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12");
        string
    }
}
<|endoftext|>


<commit_before>use winreg::RegKey;
use winreg::enums::{
    HKEY_CURRENT_USER, HKEY_USERS, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WRITE
};
use crate::keyboard::{Error, KeyboardRegKey};
use crate::types::*;
use crate::platform::*;

pub fn enable(tag: &str, product_code: &str) -> Result<(), Error> {
    let record = match KeyboardRegKey::find_by_product_code(product_code) {
        Some(v) => v,
        None => return Err(Error::NotFound)
    };

    // Generate input list item
    let lcid = crate::lcid(tag);
    let tip = InputList::from(format!("{:04X}:{}", lcid, record.regkey_id()));

    info!("D: Install layout, flag 0");
    input::install_layout(tip, 0x0).unwrap();
    // info!("D: Enable keyboard layout");
    // winuser::load_keyboard_layout(record.regkey_id());
    Ok(())
}

fn base_regkey(is_all_users: bool) -> RegKey {
    match is_all_users {
        true => {
            RegKey::predef(HKEY_USERS)
                .open_subkey_with_flags(r".DEFAULT", KEY_READ | KEY_WRITE)
                .unwrap()
        },
        false => RegKey::predef(HKEY_CURRENT_USER)
    }
}

fn kbd_layout_sub_regkey(is_all_users: bool) -> RegKey {
    base_regkey(is_all_users)
        .open_subkey_with_flags(r"Keyboard Layout\Substitutes", KEY_READ | KEY_WRITE)
        .unwrap()
}

fn kbd_layout_preload_regkey(is_all_users: bool) -> RegKey {
    base_regkey(is_all_users)
        .open_subkey_with_flags(r"Keyboard Layout\Preload", KEY_READ | KEY_WRITE)
        .unwrap()
}

/// Substitute IDs begin with 0000, then increment to d001, and continue incrementing dXXX.
fn next_substitute_id(suffix: u16) -> u32 {
    let prefix: u16 = RegKey::predef(HKEY_CURRENT_USER)
        .open_subkey_with_flags(r"Keyboard Layout\Substitutes", KEY_READ)
        .unwrap()
        .enum_values()
        .fold(0u16, |acc, x| {
            let (k, _) = x.unwrap();

            if let Ok(kk) = u32::from_str_radix(&k, 16) {
                if (kk as u16) == suffix {
                    // Move high bits down
                    let v = (kk >> 16) as u16;

                    if v >= acc {
                        return if v == 0 {
                            0xd001
                        } else {
                            v + 1
                        }
                    }
                }

                acc
            } else {
                acc
            }
        });

    ((prefix as u32) << 16) + (suffix as u32)
}

#[cfg(feature = "legacy")]
fn next_preload_id(is_all_users: bool) -> u32 {
    base_regkey(is_all_users)
        .open_subkey_with_flags(r"Keyboard Layout\Preload", KEY_READ)
        .unwrap()
        .enum_values()
        .fold(1u32, |acc, x| {
            let (k, _) = x.unwrap();

            if let Ok(v) = u32::from_str_radix(&k, 10) {
                if v >= acc {
                    v + 1
                } else {
                    acc
                }
            } else {
                acc
            }
        })
}
<commit_msg>fix legacy builds<commit_after>use registry::{Hive, Data, RegKey, Security};
use crate::keyboard::{Error, KeyboardRegKey};
use crate::types::*;
use crate::platform::*;

pub fn enable(tag: &str, product_code: &str) -> Result<(), Error> {
    let record = match KeyboardRegKey::find_by_product_code(product_code) {
        Some(v) => v,
        None => return Err(Error::NotFound)
    };

    // Generate input list item
    let lcid = crate::lcid(tag);
    let tip = InputList::from(format!("{:04X}:{}", lcid, record.regkey_id()));

    info!("D: Install layout, flag 0");
    input::install_layout(tip, 0x0).unwrap();
    // info!("D: Enable keyboard layout");
    // winuser::load_keyboard_layout(record.regkey_id());
    Ok(())
}

fn base_regkey(is_all_users: bool) -> RegKey {
    match is_all_users {
        true => {
            Hive::Users.open(".DEFAULT", Security::Read | Security::Write).unwrap()
        },
        false => Hive::CurrentUser.open("", Security::Read | Security::Write).unwrap()
    }
}

fn kbd_layout_sub_regkey(is_all_users: bool) -> RegKey {
    base_regkey(is_all_users)
        .open(r"Keyboard Layout\Substitutes", Security::Read | Security::Write)
        .unwrap()
}

fn kbd_layout_preload_regkey(is_all_users: bool) -> RegKey {
    base_regkey(is_all_users)
        .open(r"Keyboard Layout\Preload", Security::Read | Security::Write)
        .unwrap()
}

/// Substitute IDs begin with 0000, then increment to d001, and continue incrementing dXXX.
fn next_substitute_id(suffix: u16) -> u32 {
    let prefix: u16 = Hive::CurrentUser
        .open(r"Keyboard Layout\Substitutes", Security::Read)
        .unwrap()
        .values()
        .fold(0u16, |acc, x| {
            let name = x.unwrap().name().to_string_lossy();

            if let Ok(val) = u32::from_str_radix(&name, 16) {
                if (val as u16) == suffix {
                    // Move high bits down
                    let v = (val >> 16) as u16;

                    if v >= acc {
                        return if v == 0 {
                            0xd001
                        } else {
                            v + 1
                        }
                    }
                }

                acc
            } else {
                acc
            }
        });

    ((prefix as u32) << 16) + (suffix as u32)
}

#[cfg(feature = "legacy")]
fn next_preload_id(is_all_users: bool) -> u32 {
    base_regkey(is_all_users)
        .open(r"Keyboard Layout\Preload", Security::Read)
        .unwrap()
        .values()
        .fold(1u32, |acc, x| {
            let name = x.unwrap().name().to_string_lossy();

            if let Ok(v) = u32::from_str_radix(&name, 10) {
                if v >= acc {
                    v + 1
                } else {
                    acc
                }
            } else {
                acc
            }
        })
}
<|endoftext|>