<commit_before>/// Serial port management module supporting one
/// writer and multiple readers
///
/// Clients can lock a port for writing, but
/// subscribe to data from multiple ports for reads

use std::collections::HashSet;
use std::sync::mpsc::{Receiver, TryRecvError};
use std::thread;
use std::time::Duration;

use base64;

use errors::*;
use messages::*;
use sub_manager::*;
use port_manager::*;
use writelock_manager::*;
use common::*;

/// Manager manages connection state.
/// TODO Needs a better name
pub struct Manager {
  /// Manage write lock status
  writelock_manager: WriteLockManager,
  /// Manage ports
  port_manager: PortManager,
  /// Manage subscriptions
  sub_manager: SubscriptionManager,
  /// Receiver for serial requests
  receiver: Receiver<(String, SerialRequest)>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl Manager {
  ///Constructor
  pub fn new(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> Manager {
    Manager {
      writelock_manager: WriteLockManager::new(),
      port_manager: PortManager::new(),
      sub_manager: SubscriptionManager::new(),
      receiver: receiver,
      subsc_receiver: subsc_receiver,
    }
  }

  ///Spawn an instance in a new thread.
  pub fn spawn(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> thread::JoinHandle<()> {
    thread::spawn(move || { Manager::new(receiver, subsc_receiver).run(); })
  }

  /// Main loop
  fn run(&mut self) {

    // Bad ports we couldn't read from
    // A set of SerialResponse::Errors built from
    // from the serial port read/write error responses
    let mut bad_ports = HashSet::<String>::new();
    // Shutdown flag
    let mut shutdown = false;
    // Check about 30 times a second
    let sleep_dur = Duration::from_millis(33);

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      // TODO Dynamic timing loop
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
              shutdown = true;
            }
          }
        }
        Ok(req) => self.handle_serial_request(&req.0, req.1),
      }

      // Check for new data on each port
      for (port_name, result) in self.port_manager.read_all_ports() {
        match result {
          Ok(data) => {
            let response = match String::from_utf8(data) {
              // We need to send as binary
              Err(e) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: base64::encode(&e.into_bytes()),
                  base64: Some(true),
                }
              }
              Ok(s) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: s,
                  base64: Some(false),
                }
              }
            };
            self.broadcast_message_for_port(&port_name, response);
          }
          // Send data reads
          Err(e) => {
            warn!("Error reading port!");
            warn!("{}", e);
            bad_ports.insert(port_name);
          }
        }
      }

      //Handle write requests
      let mut recv_count = 0;
      let mut do_recv = true;
      while do_recv {
        recv_count += 1;
        match self.subsc_receiver.try_recv() {
          Ok(sub_request) => self.sub_manager.add_subscription(sub_request),
          Err(e) => {
            match e {
              TryRecvError::Disconnected => {
                // Does this mean all senders have disconnected?
                // Or just one?
                debug!("Got disconnected when trying to get serial request");
              }
              TryRecvError::Empty => do_recv = false,
            }
          }
        }

        // Don't let this loop get stuck here forever
        // starving the outer loop
        if recv_count == 50 {
          do_recv = false;
        }
      }

      // Cleanup bad serial ports that failed read or write
      // We remove them from everything before
      self.cleanup_bad_ports(&bad_ports);
      bad_ports.clear();
    }
  }

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&mut self, sub_id: &String, msg: SerialRequest) {
    let response = match msg {
      SerialRequest::Open { port } => self.handle_open_port(sub_id, port),
      SerialRequest::WriteLock { port } => self.handle_write_lock(sub_id, port),
      SerialRequest::ReleaseWriteLock { port } => self.handle_release_write_lock(sub_id, port),
      SerialRequest::Write { port, data, base64 } => {
        self.handle_write_port(sub_id, port, data, base64.unwrap_or(false))
      }
      SerialRequest::Close { port } => self.handle_close_port(sub_id, port),
      SerialRequest::List {} => self.handle_list_ports(sub_id),
    };
    match response {
      Ok(response) => {
        // Send acknowledge?
      }
      Err(e) => {
        warn!("Error '{}' occured handling serial request message", e);
        // Send error?
        self.send_message(&sub_id, to_serial_response_error(e));
      }
    }
  }

  /// Handle write port requests
  fn handle_write_port(
    &mut self,
    sub_id: &String,
    port_name: String,
    data: String,
    base_64: bool,
  ) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.check_owns_writelock(&port_name, &sub_id)?;
    match base_64 {
      true => {
        base64::decode(&data)
          .map_err(|e| ErrorKind::Base64(e).into())
          .and_then(|d| self.port_manager.write_port(&port_name, &d))
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
      false => {
        self
          .port_manager
          .write_port(&port_name, data.as_bytes())
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
    }
  }

  /// Handle write lock requests
  fn handle_write_lock(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self
      .writelock_manager
      .lock_port(&port_name, &sub_id)
      .map(|_| self.send_message(&sub_id, SerialResponse::WriteLocked { port: port_name }),)
  }

  /// Handle write requests
  fn handle_release_write_lock(
    &mut self,
    sub_id: &String,
    port_name: Option<String>,
  ) -> Result<()> {
    self.check_sub_id(sub_id)?;
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        Ok(
          self.send_message(
            &sub_id,
            SerialResponse::WriteLockReleased { port: port_name },
          ),
        )
      }
      Some(port_name) => {
        self
          .writelock_manager
          .unlock_port(&port_name, &sub_id)
          .map(
            |_| {
              self.send_message(
                &sub_id,
                SerialResponse::WriteLockReleased { port: Some(port_name) },
              )
            },
          )
      }
    }
  }

  /// Handle open port requests
  fn handle_open_port(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.port_manager.open_port(&port_name)?;
    self
      .sub_manager
      .add_port(&sub_id, &port_name)
      .map(|_| self.send_message(&sub_id, SerialResponse::Opened { port: port_name }),)
  }

  /// Handle list ports request
  fn handle_list_ports(&mut self, sub_id: &String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    let port_names: Result<Vec<String>> =
      self
        .port_manager
        .list_ports()
        .map(|v| v.iter().map(|v| v.port_name.clone()).collect());
    let resp = port_names.map(|pns| SerialResponse::List { ports: pns });
    self.send_message(
      &sub_id,
      resp.unwrap_or(
        SerialResponse::Error {
          display: "".to_string(),
          description: "".to_string(),
        },
      ),
    );
    Ok(())
  }

  /// Handle close port requests
  fn handle_close_port(&mut self, sub_id: &String, port_name: Option<String>) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    // Unsubscribe from ports
    match port_name {
      None => {
        self.sub_manager.clear_ports(Some(&sub_id));
        Ok(())
      }
      Some(ref pn) => self.sub_manager.remove_port(&sub_id, &pn),
    }?;
    // Remove write locks
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(sub_id);
        Ok(())
      }
      Some(ref pn) => self.writelock_manager.unlock_port(&pn, sub_id),
    }?;
    // TODO: Ensure close messages are sent, etc

    // Close ports with no subscribers
    let open_ports = self.port_manager.open_ports();
    let subscribed_ports = self.sub_manager.subscribed_ports();
    let ports_with_no_subs = open_ports.difference(&subscribed_ports);

    // For each open port that isn't subscribed,
    for port_to_close in ports_with_no_subs {
      // close it
      self.port_manager.close_port(&port_to_close);
      // remove the write lock
      self.writelock_manager.clear_lock(&port_to_close);
      // Let them know its closed
      let close_resp = SerialResponse::Closed { port: port_to_close.clone() };
      self.send_message(&sub_id, close_resp);
    }
    Ok(())
  }

  /// Cleanup any bad ports
  /// Clears out the passed in hash set
  fn cleanup_bad_ports(&mut self, bad_ports: &HashSet<String>) {
    for port_name in bad_ports.iter() {
      // Tell everyone port is sick
      let err_resp = to_serial_response_error(ErrorKind::PortReadError(port_name.to_owned()).into(),);
      self.broadcast_message_for_port(port_name, err_resp);
      // Tell everyone the sick ports were closed
      let close_resp = SerialResponse::Closed { port: port_name.clone() };
      self.broadcast_message_for_port(port_name, close_resp);
      // Close bad ports
      self.port_manager.close_port(port_name);
      // Remove write locks on bad ports
      self.writelock_manager.clear_lock(port_name);
      // Remove bad ports from subscriptions
      self.sub_manager.remove_port_from_all(port_name);
    }
    // Clear set of bad_ports
  }

  pub fn send_message(&mut self, sub_id: &String, msg: SerialResponse) {
    match self.sub_manager.send_message(sub_id, msg) {
      Err(e) => {
        warn!("Error sending serial response to sub_id '{}'", sub_id);
        let mut bad_subs = Vec::new();
        bad_subs.push(e);
        self.cleanup_bad_subs(bad_subs);
      }
      _ => {}
    }
  }

  /// Broadcast a message to all subscribers and
  /// then cleanup any subs that errored
  pub fn broadcast_message(&mut self, msg: SerialResponse) {
    let bad_subs = self.sub_manager.broadcast_message(msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Broadcast a message to all subscribers interested in the
  /// given port and then cleanup any subs that errored
  pub fn broadcast_message_for_port(&mut self, port_name: &String, msg: SerialResponse) {
    let bad_subs = self
      .sub_manager
      .broadcast_message_for_port(port_name, msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Cleanup any bad subs where a message send failed
  fn cleanup_bad_subs(&mut self, bad_subs: Vec<Error>) {
    for e in bad_subs {
      match e {
        Error(ErrorKind::SubscriberSendError(sub_id), _) => {
          self.sub_manager.end_subscription(&sub_id);
          self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        }
        _ => { /*nop*/ }
      }
    }
  }

  fn check_sub_id(&self, sub_id: &String) -> Result<()> {
    self.sub_manager.check_subscription_exists(sub_id)
  }

  fn check_owns_writelock(&self, port_name: &String, sub_id: &String) -> Result<()> {
    self
      .writelock_manager
      .check_owns_write_lock(port_name, sub_id)
  }
}
<commit_msg>Tweak docs and method visibility<commit_after>//! Manages serial port state and communication with clients,
//! and handling requests / responses

use std::collections::HashSet;
use std::sync::mpsc::{Receiver, TryRecvError};
use std::thread;
use std::time::Duration;

use base64;

use errors::*;
use messages::*;
use sub_manager::*;
use port_manager::*;
use writelock_manager::*;
use common::*;

/// Serial port management module supporting one
/// writer and multiple readers
///
/// Clients can lock a port for writing, but
/// subscribe to data from multiple ports for reads
pub struct Manager {
  /// Manage write lock status
  writelock_manager: WriteLockManager,
  /// Manage ports
  port_manager: PortManager,
  /// Manage subscriptions
  sub_manager: SubscriptionManager,
  /// Receiver for serial requests
  receiver: Receiver<(String, SerialRequest)>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl Manager {
  ///Constructor
  pub fn new(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> Manager {
    Manager {
      writelock_manager: WriteLockManager::new(),
      port_manager: PortManager::new(),
      sub_manager: SubscriptionManager::new(),
      receiver: receiver,
      subsc_receiver: subsc_receiver,
    }
  }

  ///Spawn an instance in a new thread.
  pub fn spawn(
    receiver: Receiver<(String, SerialRequest)>,
    subsc_receiver: SubscReceiver,
  ) -> thread::JoinHandle<()> {
    thread::spawn(move || { Manager::new(receiver, subsc_receiver).run(); })
  }

  /// Main loop
  fn run(&mut self) {

    // Bad ports we couldn't read from
    // A set of SerialResponse::Errors built from
    // from the serial port read/write error responses
    let mut bad_ports = HashSet::<String>::new();
    // Shutdown flag
    let mut shutdown = false;
    // Check about 30 times a second
    let sleep_dur = Duration::from_millis(33);

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      // TODO Dynamic timing loop
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
              shutdown = true;
            }
          }
        }
        Ok(req) => self.handle_serial_request(&req.0, req.1),
      }

      // Check for new data on each port
      for (port_name, result) in self.port_manager.read_all_ports() {
        match result {
          Ok(data) => {
            let response = match String::from_utf8(data) {
              // We need to send as binary
              Err(e) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: base64::encode(&e.into_bytes()),
                  base64: Some(true),
                }
              }
              Ok(s) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: s,
                  base64: Some(false),
                }
              }
            };
            self.broadcast_message_for_port(&port_name, response);
          }
          // Send data reads
          Err(e) => {
            warn!("Error reading port!");
            warn!("{}", e);
            bad_ports.insert(port_name);
          }
        }
      }

      //Handle write requests
      let mut recv_count = 0;
      let mut do_recv = true;
      while do_recv {
        recv_count += 1;
        match self.subsc_receiver.try_recv() {
          Ok(sub_request) => self.sub_manager.add_subscription(sub_request),
          Err(e) => {
            match e {
              TryRecvError::Disconnected => {
                // Does this mean all senders have disconnected?
                // Or just one?
                debug!("Got disconnected when trying to get serial request");
              }
              TryRecvError::Empty => do_recv = false,
            }
          }
        }

        // Don't let this loop get stuck here forever
        // starving the outer loop
        if recv_count == 50 {
          do_recv = false;
        }
      }

      // Cleanup bad serial ports that failed read or write
      // We remove them from everything before
      self.cleanup_bad_ports(&bad_ports);
      bad_ports.clear();
    }
  }

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&mut self, sub_id: &String, msg: SerialRequest) {
    let response = match msg {
      SerialRequest::Open { port } => self.handle_open_port(sub_id, port),
      SerialRequest::WriteLock { port } => self.handle_write_lock(sub_id, port),
      SerialRequest::ReleaseWriteLock { port } => self.handle_release_write_lock(sub_id, port),
      SerialRequest::Write { port, data, base64 } => {
        self.handle_write_port(sub_id, port, data, base64.unwrap_or(false))
      }
      SerialRequest::Close { port } => self.handle_close_port(sub_id, port),
      SerialRequest::List {} => self.handle_list_ports(sub_id),
    };
    match response {
      Ok(response) => {
        // Send acknowledge?
      }
      Err(e) => {
        warn!("Error '{}' occured handling serial request message", e);
        // Send error?
        self.send_message(&sub_id, to_serial_response_error(e));
      }
    }
  }

  /// Handle write port requests
  fn handle_write_port(
    &mut self,
    sub_id: &String,
    port_name: String,
    data: String,
    base_64: bool,
  ) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.check_owns_writelock(&port_name, &sub_id)?;
    match base_64 {
      true => {
        base64::decode(&data)
          .map_err(|e| ErrorKind::Base64(e).into())
          .and_then(|d| self.port_manager.write_port(&port_name, &d))
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
      false => {
        self
          .port_manager
          .write_port(&port_name, data.as_bytes())
          .map(|_| self.send_message(&sub_id, SerialResponse::Wrote { port: port_name }),)
      }
    }
  }

  /// Handle write lock requests
  fn handle_write_lock(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self
      .writelock_manager
      .lock_port(&port_name, &sub_id)
      .map(|_| self.send_message(&sub_id, SerialResponse::WriteLocked { port: port_name }),)
  }

  /// Handle write requests
  fn handle_release_write_lock(
    &mut self,
    sub_id: &String,
    port_name: Option<String>,
  ) -> Result<()> {
    self.check_sub_id(sub_id)?;
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        Ok(
          self.send_message(
            &sub_id,
            SerialResponse::WriteLockReleased { port: port_name },
          ),
        )
      }
      Some(port_name) => {
        self
          .writelock_manager
          .unlock_port(&port_name, &sub_id)
          .map(
            |_| {
              self.send_message(
                &sub_id,
                SerialResponse::WriteLockReleased { port: Some(port_name) },
              )
            },
          )
      }
    }
  }

  /// Handle open port requests
  fn handle_open_port(&mut self, sub_id: &String, port_name: String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    self.port_manager.open_port(&port_name)?;
    self
      .sub_manager
      .add_port(&sub_id, &port_name)
      .map(|_| self.send_message(&sub_id, SerialResponse::Opened { port: port_name }),)
  }

  /// Handle list ports request
  fn handle_list_ports(&mut self, sub_id: &String) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    let port_names: Result<Vec<String>> =
      self
        .port_manager
        .list_ports()
        .map(|v| v.iter().map(|v| v.port_name.clone()).collect());
    let resp = port_names.map(|pns| SerialResponse::List { ports: pns });
    self.send_message(
      &sub_id,
      resp.unwrap_or(
        SerialResponse::Error {
          display: "".to_string(),
          description: "".to_string(),
        },
      ),
    );
    Ok(())
  }

  /// Handle close port requests
  fn handle_close_port(&mut self, sub_id: &String, port_name: Option<String>) -> Result<()> {
    self.check_sub_id(&sub_id)?;
    // Unsubscribe from ports
    match port_name {
      None => {
        self.sub_manager.clear_ports(Some(&sub_id));
        Ok(())
      }
      Some(ref pn) => self.sub_manager.remove_port(&sub_id, &pn),
    }?;
    // Remove write locks
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(sub_id);
        Ok(())
      }
      Some(ref pn) => self.writelock_manager.unlock_port(&pn, sub_id),
    }?;
    // TODO: Ensure close messages are sent, etc

    // Close ports with no subscribers
    let open_ports = self.port_manager.open_ports();
    let subscribed_ports = self.sub_manager.subscribed_ports();
    let ports_with_no_subs = open_ports.difference(&subscribed_ports);

    // For each open port that isn't subscribed,
    for port_to_close in ports_with_no_subs {
      // close it
      self.port_manager.close_port(&port_to_close);
      // remove the write lock
      self.writelock_manager.clear_lock(&port_to_close);
      // Let them know its closed
      let close_resp = SerialResponse::Closed { port: port_to_close.clone() };
      self.send_message(&sub_id, close_resp);
    }
    Ok(())
  }

  /// Cleanup any bad ports
  /// Clears out the passed in hash set
  fn cleanup_bad_ports(&mut self, bad_ports: &HashSet<String>) {
    for port_name in bad_ports.iter() {
      // Tell everyone port is sick
      let err_resp = to_serial_response_error(ErrorKind::PortReadError(port_name.to_owned()).into(),);
      self.broadcast_message_for_port(port_name, err_resp);
      // Tell everyone the sick ports were closed
      let close_resp = SerialResponse::Closed { port: port_name.clone() };
      self.broadcast_message_for_port(port_name, close_resp);
      // Close bad ports
      self.port_manager.close_port(port_name);
      // Remove write locks on bad ports
      self.writelock_manager.clear_lock(port_name);
      // Remove bad ports from subscriptions
      self.sub_manager.remove_port_from_all(port_name);
    }
    // Clear set of bad_ports
  }

  fn send_message(&mut self, sub_id: &String, msg: SerialResponse) {
    match self.sub_manager.send_message(sub_id, msg) {
      Err(e) => {
        warn!("Error sending serial response to sub_id '{}'", sub_id);
        let mut bad_subs = Vec::new();
        bad_subs.push(e);
        self.cleanup_bad_subs(bad_subs);
      }
      _ => {}
    }
  }

  /// Broadcast a message to all subscribers and
  /// then cleanup any subs that errored
  fn broadcast_message(&mut self, msg: SerialResponse) {
    let bad_subs = self.sub_manager.broadcast_message(msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Broadcast a message to all subscribers interested in the
  /// given port and then cleanup any subs that errored
  fn broadcast_message_for_port(&mut self, port_name: &String, msg: SerialResponse) {
    let bad_subs = self
      .sub_manager
      .broadcast_message_for_port(port_name, msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Cleanup any bad subs where a message send failed
  fn cleanup_bad_subs(&mut self, bad_subs: Vec<Error>) {
    for e in bad_subs {
      match e {
        Error(ErrorKind::SubscriberSendError(sub_id), _) => {
          self.sub_manager.end_subscription(&sub_id);
          self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        }
        _ => { /*nop*/ }
      }
    }
  }

  fn check_sub_id(&self, sub_id: &String) -> Result<()> {
    self.sub_manager.check_subscription_exists(sub_id)
  }

  fn check_owns_writelock(&self, port_name: &String, sub_id: &String) -> Result<()> {
    self
      .writelock_manager
      .check_owns_write_lock(port_name, sub_id)
  }
}
<|endoftext|>


<commit_before>//! Selection sort algorithm.
//!
//! The `selection` module contains the simple sorting algorithm "Selection Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Selection_sort

use std::fmt::Debug;

/// Simple sort: selection sort.
///
/// # Details
///
/// Selection sort is one of the simplest sorting algorithm. The list to sort is split into two
/// sections; the first with the sorted element (starting empty) and the second with the remaining
/// element (starting full). At every iteration, the smallest element in the remaining list is
/// found and placed at the end of the sorted list.
///
/// This function takes an immutable reference vector of any type and returns a vector of `usize`
/// of the same length containing the indices of the initial vector sorted.
///
/// # Scaling
///
/// Selection sort in scale as O(N^2) since for all elements to sort, the algorithm will compare it
/// with every (remaining) elements.
///
/// Insertion sort is still useful as it is quite simple.
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::simplesorts::selection::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: Ord + Debug>(array: &mut Vec<T>) {
    println!("input array:  {:?}", array);

    if !array.is_empty() {
        // Let's loop over the input array, skipping last value (important as we want to get a
        // slice of the following values).
        let n = array.len();
        for i in 0..n-1 {
            println!("    i: {:?}", i);

            // Find index of the minimum value in the slice of values following the i^th element.
            let j = {
                let int_slice = &array[i+1..];
                println!("        array:        {:?}", array);
                println!("        int_slice:    {:?}", int_slice);
                // k now holds the index (of "array") of the minimum element of "int_slice", or the
                // value "i" of the current element of "array" (which should be the less than
                // all elements of "int_slice").
                // "k" is a tuple containing the smallest element of "int_slice" and its index.
                //     k.0: Index of "int_slice" of its smallest value.
                //     k.1: Smallest value of "int_slice".
                let k = int_slice.iter().enumerate().fold(
                    (0, int_slice.first().unwrap()), |acc, item| {
                        if acc.1 > item.1 { item } else { acc }
                });

                // Return from the block the smallest element between the one at index "i" of
                // the "array" and the smallest one from the "int_slice" array.
                // NOTE: Since "k" worked on the subarray "int_slice", it's first element is the
                //       i^th element of "array". If "k" is actually smaller than "array[i]", we
                //       need to adapt the index as stored in "k.0".
                if k.1 < &array[i] { i + k.0 + 1 } else { i }
            };
            println!("            j: {:?}   array[i]={:?}   array[j]={:?}", j, array[i], array[j]);

            array.swap(i, j);
            println!("        new array:    {:?}", array);
        }
    }

    println!("output array: {:?}", array);

    // panic!("Ok");
}
<commit_msg>Don't panic<commit_after>//! Selection sort algorithm.
//!
//! The `selection` module contains the simple sorting algorithm "Selection Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Selection_sort

use std::fmt::Debug;

/// Simple sort: selection sort.
///
/// # Details
///
/// Selection sort is one of the simplest sorting algorithm. The list to sort is split into two
/// sections; the first with the sorted element (starting empty) and the second with the remaining
/// element (starting full). At every iteration, the smallest element in the remaining list is
/// found and placed at the end of the sorted list.
///
/// This function takes an immutable reference vector of any type and returns a vector of `usize`
/// of the same length containing the indices of the initial vector sorted.
///
/// # Scaling
///
/// Selection sort in scale as O(N^2) since for all elements to sort, the algorithm will compare it
/// with every (remaining) elements.
///
/// Insertion sort is still useful as it is quite simple.
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::simplesorts::selection::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: Ord + Debug>(array: &mut Vec<T>) {
    println!("input array:  {:?}", array);

    if !array.is_empty() {
        // Let's loop over the input array, skipping last value (important as we want to get a
        // slice of the following values).
        let n = array.len();
        for i in 0..n-1 {
            println!("    i: {:?}", i);

            // Find index of the minimum value in the slice of values following the i^th element.
            let j = {
                let int_slice = &array[i+1..];
                println!("        array:        {:?}", array);
                println!("        int_slice:    {:?}", int_slice);
                // k now holds the index (of "array") of the minimum element of "int_slice", or the
                // value "i" of the current element of "array" (which should be the less than
                // all elements of "int_slice").
                // "k" is a tuple containing the smallest element of "int_slice" and its index.
                //     k.0: Index of "int_slice" of its smallest value.
                //     k.1: Smallest value of "int_slice".
                let k = int_slice.iter().enumerate().fold(
                    (0, int_slice.first().unwrap()), |acc, item| {
                        if acc.1 > item.1 { item } else { acc }
                });

                // Return from the block the smallest element between the one at index "i" of
                // the "array" and the smallest one from the "int_slice" array.
                // NOTE: Since "k" worked on the subarray "int_slice", it's first element is the
                //       i^th element of "array". If "k" is actually smaller than "array[i]", we
                //       need to adapt the index as stored in "k.0".
                if k.1 < &array[i] { i + k.0 + 1 } else { i }
            };
            println!("            j: {:?}   array[i]={:?}   array[j]={:?}", j, array[i], array[j]);

            array.swap(i, j);
            println!("        new array:    {:?}", array);
        }
    }

    println!("output array: {:?}", array);
}
<|endoftext|>


<commit_before>extern crate saddle_points;

use saddle_points::find_saddle_points;

// We don't care about order
fn find_sorted_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let mut result = saddle_points::find_saddle_points(input);
    result.sort();
    result
}

#[test]
fn identify_single_saddle_point() {
    let input = vec![
        vec![9, 8, 7],
        vec![5, 3, 2],
        vec![6, 6, 7],
    ];
    assert_eq!(vec![(1, 0)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_empty_matrix() {
    let input = vec![vec![], vec![], vec![]];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_lack_of_saddle_point() {
    let input = vec![
        vec![1, 2, 3],
        vec![3, 1, 2],
        vec![2, 3, 1],
    ];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn multiple_saddle_points_in_col() {
    let input = vec![
        vec![4, 5, 4],
        vec![3, 5, 5],
        vec![1, 5, 4],
    ];
    assert_eq!(
        vec![(0, 1), (1, 1), (2, 1)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn multiple_saddle_points_in_row() {
    let input = vec![
        vec![6, 7, 8],
        vec![5, 5, 5],
        vec![7, 5, 6],
    ];
    assert_eq!(
        vec![(1, 0), (1, 1), (1, 2)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn identify_bottom_right_saddle_point() {
    let input = vec![
        vec![8, 7, 9],
        vec![6, 7, 6],
        vec![3, 2, 5],
    ];
    assert_eq!(vec![(2, 2)], find_saddle_points(&input));
}

// track specific as of v1.3
#[test]
#[ignore]
fn non_square_matrix_high() {
    let input = vec![
        vec![1, 5],
        vec![3, 6],
        vec![2, 7],
        vec![3, 8],
    ];
    assert_eq!(vec![(0, 1)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn non_square_matrix_wide() {
    let input = vec![
        vec![3, 1, 3],
        vec![3, 2, 4]
    ];
    assert_eq!(vec![(0, 0), (0, 2)], find_sorted_saddle_points(&input));
}

#[test]
#[ignore]
fn single_column_matrix() {
    let input = vec![
        vec![2],
        vec![1],
        vec![4],
        vec![1],
    ];
    assert_eq!(vec![(1, 0), (3, 0)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn single_row_matrix() {
    let input = vec![
        vec![2, 5, 3, 5],
    ];
    assert_eq!(vec![(0, 1), (0, 3)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_all_saddle_points() {
    let input = vec![
        vec![5, 5, 5],
        vec![5, 5, 5],
        vec![5, 5, 5],
    ];
    assert_eq!(vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)], find_saddle_points(&input));
}

<commit_msg>saddle-points: Ignore order of results (#725)<commit_after>extern crate saddle_points;

use saddle_points::find_saddle_points;

// We don't care about order
fn find_sorted_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let mut result = saddle_points::find_saddle_points(input);
    result.sort();
    result
}

#[test]
fn identify_single_saddle_point() {
    let input = vec![
        vec![9, 8, 7],
        vec![5, 3, 2],
        vec![6, 6, 7],
    ];
    assert_eq!(vec![(1, 0)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_empty_matrix() {
    let input = vec![vec![], vec![], vec![]];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_lack_of_saddle_point() {
    let input = vec![
        vec![1, 2, 3],
        vec![3, 1, 2],
        vec![2, 3, 1],
    ];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn multiple_saddle_points_in_col() {
    let input = vec![
        vec![4, 5, 4],
        vec![3, 5, 5],
        vec![1, 5, 4],
    ];
    assert_eq!(
        vec![(0, 1), (1, 1), (2, 1)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn multiple_saddle_points_in_row() {
    let input = vec![
        vec![6, 7, 8],
        vec![5, 5, 5],
        vec![7, 5, 6],
    ];
    assert_eq!(
        vec![(1, 0), (1, 1), (1, 2)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn identify_bottom_right_saddle_point() {
    let input = vec![
        vec![8, 7, 9],
        vec![6, 7, 6],
        vec![3, 2, 5],
    ];
    assert_eq!(vec![(2, 2)], find_saddle_points(&input));
}

// track specific as of v1.3
#[test]
#[ignore]
fn non_square_matrix_high() {
    let input = vec![
        vec![1, 5],
        vec![3, 6],
        vec![2, 7],
        vec![3, 8],
    ];
    assert_eq!(vec![(0, 1)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn non_square_matrix_wide() {
    let input = vec![
        vec![3, 1, 3],
        vec![3, 2, 4]
    ];
    assert_eq!(vec![(0, 0), (0, 2)], find_sorted_saddle_points(&input));
}

#[test]
#[ignore]
fn single_column_matrix() {
    let input = vec![
        vec![2],
        vec![1],
        vec![4],
        vec![1],
    ];
    assert_eq!(vec![(1, 0), (3, 0)], find_sorted_saddle_points(&input));
}

#[test]
#[ignore]
fn single_row_matrix() {
    let input = vec![
        vec![2, 5, 3, 5],
    ];
    assert_eq!(vec![(0, 1), (0, 3)], find_sorted_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_all_saddle_points() {
    let input = vec![
        vec![5, 5, 5],
        vec![5, 5, 5],
        vec![5, 5, 5],
    ];
    assert_eq!(vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)], find_saddle_points(&input));
}

<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

#[derive(Debug, Default)]
pub(crate) struct Popularity {
    inner: HashSet<Rc<str>>,
}

#[derive(Debug, Default)]
pub(crate) struct Pool {
    inner: HashMap<Rc<str>, usize>,
}

impl Popularity {
    pub fn vote(&mut self, string: &str) -> Rc<str> {
        if let Some(result) = self.inner.get(string) {
            return result.clone();
        }

        let result: Rc<str> = string.to_owned().into();

        self.inner.insert(result.clone());

        result
    }

    pub fn report(&self) -> Vec<Rc<str>> {
        let mut result: Vec<_> = self.inner.iter().map(|x| x.clone()).collect();
        result.sort_by(|p, q| {
            Rc::strong_count(p)
                .cmp(&Rc::strong_count(q))
                .reverse()
                .then_with(|| p.cmp(q))
        });

        result
    }
}

impl Pool {
    pub fn r#use(&self, string: &str) -> usize {
        self.inner[string]
    }
}

impl From<&Vec<Rc<str>>> for Pool {
    fn from(report: &Vec<Rc<str>>) -> Self {
        let mut result = Self::default();

        for string in report {
            result.inner.insert(string.clone(), result.inner.len());
        }

        result
    }
}
<commit_msg>exclude unused strings from data.string.json<commit_after>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

#[derive(Debug, Default)]
pub(crate) struct Popularity {
    inner: HashSet<Rc<str>>,
}

#[derive(Debug, Default)]
pub(crate) struct Pool {
    inner: HashMap<Rc<str>, usize>,
}

impl Popularity {
    pub fn vote(&mut self, string: &str) -> Rc<str> {
        if let Some(result) = self.inner.get(string) {
            return result.clone();
        }

        let result: Rc<str> = string.to_owned().into();

        self.inner.insert(result.clone());

        result
    }

    pub fn report(mut self) -> Vec<Rc<str>> {
        let mut result: Vec<_> = self
            .inner
            .drain()
            .filter(|x| Rc::strong_count(x) > 1)
            .map(|x| x.clone())
            .collect();

        result.sort_by(|p, q| {
            Rc::strong_count(p)
                .cmp(&Rc::strong_count(q))
                .reverse()
                .then_with(|| p.cmp(q))
        });

        result
    }
}

impl Pool {
    pub fn r#use(&self, string: &str) -> usize {
        self.inner[string]
    }
}

impl From<&Vec<Rc<str>>> for Pool {
    fn from(report: &Vec<Rc<str>>) -> Self {
        let mut result = Self::default();

        for string in report {
            result.inner.insert(string.clone(), result.inner.len());
        }

        result
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{AbstractCFTypeRef, CFTypeID, CFTypeRef, CFWrapper};

use std::cast;
use std::libc::{c_void, c_char, size_t};
use std::ptr;

pub type CGDataProviderGetBytesCallback = *u8;
pub type CGDataProviderReleaseInfoCallback = *u8;
pub type CGDataProviderRewindCallback = *u8;
pub type CGDataProviderSkipBytesCallback = *u8;
pub type CGDataProviderSkipForwardCallback = *u8;

pub type CGDataProviderGetBytePointerCallback = *u8;
pub type CGDataProviderGetBytesAtOffsetCallback = *u8;
pub type CGDataProviderReleaseBytePointerCallback = *u8;
pub type CGDataProviderReleaseDataCallback = *u8;
pub type CGDataProviderGetBytesAtPositionCallback = *u8;

struct __CGDataProvider { private: () }
pub type CGDataProviderRef = *__CGDataProvider;

impl AbstractCFTypeRef for CGDataProviderRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }

    fn type_id() -> CFTypeID {
        unsafe {
            CGDataProviderGetTypeID()
        }
    }
}

pub type CGDataProvider = CFWrapper<CGDataProviderRef, (), ()>;

pub fn new_from_buffer(buf: *u8, len: uint) -> CGDataProvider {
    unsafe {
        let result = CGDataProviderCreateWithData(
            ptr::null(),
            cast::transmute(buf),
            len as size_t,
            ptr::null());

        CFWrapper::wrap_owned(result)
    }
}

#[nolink]
#[link_args="-framework ApplicationServices"]
pub extern {
    //fn CGDataProviderCopyData
    //fn CGDataProviderCreateDirect
    //fn CGDataProviderCreateSequential
    //fn CGDataProviderCreateWithCFData
    fn CGDataProviderCreateWithData(info: *c_void,
                                    data: *c_void,
                                    size: size_t,
                                    releaseData: CGDataProviderReleaseDataCallback
                                   ) -> CGDataProviderRef;
    fn CGDataProviderCreateWithFilename(filename: *c_char) -> CGDataProviderRef;
    //fn CGDataProviderCreateWithURL
    fn CGDataProviderGetTypeID() -> CFTypeID;
    fn CGDataProviderRelease(provider: CGDataProviderRef);
    fn CGDataProviderRetain(provider: CGDataProviderRef) -> CGDataProviderRef;
}
<commit_msg>Fix visibility for mac.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{AbstractCFTypeRef, CFTypeID, CFTypeRef, CFWrapper};

use std::cast;
use std::libc::{c_void, c_char, size_t};
use std::ptr;

pub type CGDataProviderGetBytesCallback = *u8;
pub type CGDataProviderReleaseInfoCallback = *u8;
pub type CGDataProviderRewindCallback = *u8;
pub type CGDataProviderSkipBytesCallback = *u8;
pub type CGDataProviderSkipForwardCallback = *u8;

pub type CGDataProviderGetBytePointerCallback = *u8;
pub type CGDataProviderGetBytesAtOffsetCallback = *u8;
pub type CGDataProviderReleaseBytePointerCallback = *u8;
pub type CGDataProviderReleaseDataCallback = *u8;
pub type CGDataProviderGetBytesAtPositionCallback = *u8;

struct __CGDataProvider { private: () }
pub type CGDataProviderRef = *__CGDataProvider;

impl AbstractCFTypeRef for CGDataProviderRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }

    fn type_id() -> CFTypeID {
        unsafe {
            CGDataProviderGetTypeID()
        }
    }
}

pub type CGDataProvider = CFWrapper<CGDataProviderRef, (), ()>;

pub fn new_from_buffer(buf: *u8, len: uint) -> CGDataProvider {
    unsafe {
        let result = CGDataProviderCreateWithData(
            ptr::null(),
            cast::transmute(buf),
            len as size_t,
            ptr::null());

        CFWrapper::wrap_owned(result)
    }
}

#[nolink]
#[link_args="-framework ApplicationServices"]
extern {
    //fn CGDataProviderCopyData
    //fn CGDataProviderCreateDirect
    //fn CGDataProviderCreateSequential
    //fn CGDataProviderCreateWithCFData
    fn CGDataProviderCreateWithData(info: *c_void,
                                    data: *c_void,
                                    size: size_t,
                                    releaseData: CGDataProviderReleaseDataCallback
                                   ) -> CGDataProviderRef;
    fn CGDataProviderCreateWithFilename(filename: *c_char) -> CGDataProviderRef;
    //fn CGDataProviderCreateWithURL
    fn CGDataProviderGetTypeID() -> CFTypeID;
    fn CGDataProviderRelease(provider: CGDataProviderRef);
    fn CGDataProviderRetain(provider: CGDataProviderRef) -> CGDataProviderRef;
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeSet, HashSet};
use std::hash::{Hash, Hasher};
use std::mem;

type Book = u32;
type GroupedBasket = Vec<Group>;
type Price = u32;
const BOOK_PRICE: Price = 800;

#[derive(Debug, Clone, PartialEq, Eq)]
struct Group(RefCell<BTreeSet<Book>>);

impl Group {
    fn new() -> Group {
        Group(RefCell::new(BTreeSet::new()))
    }

    fn new_containing(book: Book) -> Group {
        let g = Group::new();
        g.0.borrow_mut().insert(book);
        g
    }

    fn price(&self) -> Price {
        (self.0.borrow().len() as Price)
            * BOOK_PRICE
            * match self.0.borrow().len() {
                2 => 95,
                3 => 90,
                4 => 80,
                5 => 75,
                _ => 100,
            }
            / 100
    }
}

impl Ord for Group {
    // we want to order groups first by qty contained DESC, then by lowest value ASC
    fn cmp(&self, other: &Group) -> Ordering {
        match other.0.borrow().len().cmp(&self.0.borrow().len()) {
            Ordering::Equal => {
                if self.0.borrow().is_empty() {
                    Ordering::Equal
                } else {
                    self.0
                        .borrow()
                        .iter()
                        .next()
                        .unwrap()
                        .cmp(other.0.borrow().iter().next().unwrap())
                }
            }
            otherwise => otherwise,
        }
    }
}

impl PartialOrd for Group {
    fn partial_cmp(&self, other: &Group) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Hash for Group {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.0.borrow().hash(hasher);
    }
}

fn basket_price(basket: &GroupedBasket) -> Price {
    basket.iter().map(|g| g.price()).sum()
}

/// Compute the hash of a GroupedBasket
///
/// Note that we don't actually care at all about the _values_ within
/// the groups, only their lengths. Therefore, let's hash not the actual
/// GB but its lengths.
fn hash_of(basket: &GroupedBasket) -> u64 {
    let lengths = basket
        .iter()
        .map(|g| g.0.borrow().len())
        .collect::<Vec<_>>();
    let mut hasher = DefaultHasher::new();
    lengths.hash(&mut hasher);
    hasher.finish()
}

pub fn lowest_price(books: &[Book]) -> Price {
    DecomposeGroups::new(books)
        .map(|gb| basket_price(&gb))
        .min()
        .unwrap_or(0)
}

struct DecomposeGroups {
    prev_states: HashSet<u64>,
    next: Option<GroupedBasket>,
}

impl Iterator for DecomposeGroups {
    type Item = GroupedBasket;
    fn next(&mut self) -> Option<Self::Item> {
        // our goal here: produce a stream of valid groups, differentiated by their
        // counts, from most compact to most dispersed.
        //
        // Algorithm:
        //  - Start with the most compact groups possible
        //  - If the number of groups == 0 or the max population of any group == 1, return None
        //  - For every item in the most populous group:
        //      - Try removing it and adding it to a smaller group.
        //          - Can any smaller group accept it? if yes, move it there and return
        //  - If it cannot be added to any smaller group, try the next item from this set
        //  - If no item from the most populous group can be added to any smaller group,
        //    then move the last item from the most populous group into a new group, alone,
        //    and return
        let return_value = self.next.clone();
        if let Some(groups) = mem::replace(&mut self.next, None) {
            if !(groups.is_empty() || groups.iter().all(|g| g.0.borrow().len() == 1)) {
                let mut hypothetical;
                for mpg_book in groups[0].0.borrow().iter() {
                    for (idx, other_group) in groups[1..].iter().enumerate() {
                        if !other_group.0.borrow().contains(mpg_book) {
                            hypothetical = groups.clone();
                            hypothetical[0].0.borrow_mut().remove(mpg_book);
                            hypothetical[1 + idx].0.borrow_mut().insert(*mpg_book);
                            hypothetical.sort();
                            let hypothetical_hash = hash_of(&hypothetical);
                            if !self.prev_states.contains(&hypothetical_hash) {
                                self.prev_states.insert(hypothetical_hash);
                                mem::replace(&mut self.next, Some(hypothetical));
                                return return_value;
                            }
                        }
                    }
                }
                // we've gone through all the items of the most populous group,
                // and none of them can be added to any other existing group.
                // We need to create a new group;
                let book = {
                    let backing_bt = groups[0].0.borrow();
                    let mut book_iter = backing_bt.iter();
                    *book_iter.next().unwrap()
                };
                hypothetical = groups.clone();
                hypothetical[0].0.borrow_mut().remove(&book);
                hypothetical.push(Group::new_containing(book));
                hypothetical.sort();
                self.prev_states.insert(hash_of(&hypothetical));
                mem::replace(&mut self.next, Some(hypothetical));
            }
        }
        return_value
    }
}

impl DecomposeGroups {
    fn new(books: &[Book]) -> DecomposeGroups {
        let mut book_groups = GroupedBasket::new();
        'nextbook: for book in books {
            for Group(book_group) in book_groups.iter() {
                if !book_group.borrow().contains(&book) {
                    book_group.borrow_mut().insert(*book);
                    continue 'nextbook;
                }
            }
            // if we're here, we still haven't found a place for the book.
            // better add it to a new group
            book_groups.push(Group::new_containing(*book));
        }
        book_groups.sort();

        DecomposeGroups {
            next: Some(book_groups),
            prev_states: HashSet::new(),
        }
    }
}
<commit_msg>book-store: don't use std::mem::replace unnecessarily (#977)<commit_after>use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeSet, HashSet};
use std::hash::{Hash, Hasher};
use std::mem;

type Book = u32;
type GroupedBasket = Vec<Group>;
type Price = u32;
const BOOK_PRICE: Price = 800;

#[derive(Debug, Clone, PartialEq, Eq)]
struct Group(RefCell<BTreeSet<Book>>);

impl Group {
    fn new() -> Group {
        Group(RefCell::new(BTreeSet::new()))
    }

    fn new_containing(book: Book) -> Group {
        let g = Group::new();
        g.0.borrow_mut().insert(book);
        g
    }

    fn price(&self) -> Price {
        (self.0.borrow().len() as Price)
            * BOOK_PRICE
            * match self.0.borrow().len() {
                2 => 95,
                3 => 90,
                4 => 80,
                5 => 75,
                _ => 100,
            }
            / 100
    }
}

impl Ord for Group {
    // we want to order groups first by qty contained DESC, then by lowest value ASC
    fn cmp(&self, other: &Group) -> Ordering {
        match other.0.borrow().len().cmp(&self.0.borrow().len()) {
            Ordering::Equal => {
                if self.0.borrow().is_empty() {
                    Ordering::Equal
                } else {
                    self.0
                        .borrow()
                        .iter()
                        .next()
                        .unwrap()
                        .cmp(other.0.borrow().iter().next().unwrap())
                }
            }
            otherwise => otherwise,
        }
    }
}

impl PartialOrd for Group {
    fn partial_cmp(&self, other: &Group) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Hash for Group {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.0.borrow().hash(hasher);
    }
}

fn basket_price(basket: &GroupedBasket) -> Price {
    basket.iter().map(|g| g.price()).sum()
}

/// Compute the hash of a GroupedBasket
///
/// Note that we don't actually care at all about the _values_ within
/// the groups, only their lengths. Therefore, let's hash not the actual
/// GB but its lengths.
fn hash_of(basket: &GroupedBasket) -> u64 {
    let lengths = basket
        .iter()
        .map(|g| g.0.borrow().len())
        .collect::<Vec<_>>();
    let mut hasher = DefaultHasher::new();
    lengths.hash(&mut hasher);
    hasher.finish()
}

pub fn lowest_price(books: &[Book]) -> Price {
    DecomposeGroups::new(books)
        .map(|gb| basket_price(&gb))
        .min()
        .unwrap_or(0)
}

struct DecomposeGroups {
    prev_states: HashSet<u64>,
    next: Option<GroupedBasket>,
}

impl Iterator for DecomposeGroups {
    type Item = GroupedBasket;
    fn next(&mut self) -> Option<Self::Item> {
        // our goal here: produce a stream of valid groups, differentiated by their
        // counts, from most compact to most dispersed.
        //
        // Algorithm:
        //  - Start with the most compact groups possible
        //  - If the number of groups == 0 or the max population of any group == 1, return None
        //  - For every item in the most populous group:
        //      - Try removing it and adding it to a smaller group.
        //          - Can any smaller group accept it? if yes, move it there and return
        //  - If it cannot be added to any smaller group, try the next item from this set
        //  - If no item from the most populous group can be added to any smaller group,
        //    then move the last item from the most populous group into a new group, alone,
        //    and return
        let return_value = self.next.clone();
        if let Some(groups) = mem::replace(&mut self.next, None) {
            if !(groups.is_empty() || groups.iter().all(|g| g.0.borrow().len() == 1)) {
                let mut hypothetical;
                for mpg_book in groups[0].0.borrow().iter() {
                    for (idx, other_group) in groups[1..].iter().enumerate() {
                        if !other_group.0.borrow().contains(mpg_book) {
                            hypothetical = groups.clone();
                            hypothetical[0].0.borrow_mut().remove(mpg_book);
                            hypothetical[1 + idx].0.borrow_mut().insert(*mpg_book);
                            hypothetical.sort();
                            let hypothetical_hash = hash_of(&hypothetical);
                            if !self.prev_states.contains(&hypothetical_hash) {
                                self.prev_states.insert(hypothetical_hash);
                                self.next = Some(hypothetical);
                                return return_value;
                            }
                        }
                    }
                }
                // we've gone through all the items of the most populous group,
                // and none of them can be added to any other existing group.
                // We need to create a new group;
                let book = {
                    let backing_bt = groups[0].0.borrow();
                    let mut book_iter = backing_bt.iter();
                    *book_iter.next().unwrap()
                };
                hypothetical = groups.clone();
                hypothetical[0].0.borrow_mut().remove(&book);
                hypothetical.push(Group::new_containing(book));
                hypothetical.sort();
                self.prev_states.insert(hash_of(&hypothetical));
                self.next = Some(hypothetical);
            }
        }
        return_value
    }
}

impl DecomposeGroups {
    fn new(books: &[Book]) -> DecomposeGroups {
        let mut book_groups = GroupedBasket::new();
        'nextbook: for book in books {
            for Group(book_group) in book_groups.iter() {
                if !book_group.borrow().contains(&book) {
                    book_group.borrow_mut().insert(*book);
                    continue 'nextbook;
                }
            }
            // if we're here, we still haven't found a place for the book.
            // better add it to a new group
            book_groups.push(Group::new_containing(*book));
        }
        book_groups.sort();

        DecomposeGroups {
            next: Some(book_groups),
            prev_states: HashSet::new(),
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;

pub fn build() {
    use std::path::Path;

    let out_dir = ::std::env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("named.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named.rs");
    build_colors(&mut writer);
    let dest_path = Path::new(&out_dir).join("named_gradients.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named_gradients.rs");
    build_gradients(&mut writer);
}

#[cfg(feature = "named")]
pub fn build_colors(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader =
        BufReader::new(File::open("build/svg_colors.txt").expect("could not open svg_colors.txt"));
    let mut entries = vec![];

    for line in reader.lines() {
        let line = line.unwrap();
        let mut parts = line.split('\t');
        let name = parts.next().expect("couldn't get the color name");
        let mut rgb = parts
            .next()
            .unwrap_or_else(|| panic!("couldn't get color for {}", name))
            .split(", ");
        let red: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get red for {}", name));
        let green: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get green for {}", name));
        let blue: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get blue for {}", name));

        writeln!(writer, "\n///

", name).unwrap();
        writeln!(writer, "pub const {}: crate::rgb::Srgb<u8> = crate::rgb::Srgb {{ red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData }};", name.to_uppercase(), red, green, blue).unwrap();

        entries.push((name.to_owned(), name.to_uppercase()));
    }

    gen_from_str(writer, &entries)
}

#[cfg(feature = "named_gradients")]
pub fn build_gradients(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader =
        BufReader::new(File::open("build/svg_gradients_mpl.txt").expect("could not open svg_gradients_mpl.txt"));

    let mut line_iter = reader.lines();
    while let Some(Ok(line)) = line_iter.next(){
        //empty lines are allowed
        if line.is_empty() {continue;}
        let mut parts = line.split_whitespace();
        //every line should have the same info: name type number_of_colors [\n red green blue]^number_of_colors
        let name = parts.next().expect("couldn't get the color name");
        let color_type = parts.next().expect("couldn't get the type of the colors");
        //we assume that color_type is a rgb type
        let color_type = format!("crate::rgb::{}", color_type);
        let number_of_colors : usize = parts.next().expect("couldn't get the number of colors")
            .parse().unwrap_or_else(|_| panic!("couldn't parse the number of colors for color {}", name));
        writeln!(writer, "/// New matplotlib colormap by Nathaniel J. Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.").unwrap();
        writeln!(writer, "/// This gradient is perfectly perceptually-uniform, both in regular form and also when converted to black-and-white.").unwrap();
        //writeln!(writer, "/// The colormap is released under the CC0 license public domain dedication.").unwrap();
        write!(writer,
            "pub const {0}: crate::gradient::Gradient<{1}, [(f32,{1});{2}]> = crate::gradient::Gradient([",
            name.to_uppercase(), color_type, number_of_colors).unwrap();
        for i in 0..number_of_colors {
            let color = line_iter
                .next()
                .unwrap_or_else(|| panic!("less lines than stated colors in gradient {}", name))
                .unwrap_or_else(|_| panic!("couldn't read the {}th line of color {}", i, name));
            let mut rgb = color.split(",");
            let red: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th red-value for {}", i, name));
            let green: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th green-value for {}", i, name));
            let blue: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th blue-value for {}", i, name));
            write!(writer, "({:.10},{}{{red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData}}),", (i as f32/number_of_colors as f32), color_type, red, green, blue).unwrap();
        }
        write!(writer, "]);\n").unwrap();
    }
}

#[cfg(feature = "named_from_str")]
fn gen_from_str(writer: &mut File, entries: &[(String, String)]) {
    use std::io::Write;

    let mut map = ::phf_codegen::Map::new();
    for &(ref key, ref value) in entries {
        map.entry(&**key, value);
    }
    write!(
        writer,
        "static COLORS: ::phf::Map<&'static str, crate::rgb::Srgb<u8>> = {};",
        map.build()
    )
    .unwrap();
}

#[cfg(not(feature = "named"))]
pub fn build_colors(_writer: &mut File) {}

#[allow(unused)]
#[cfg(not(feature = "named_from_str"))]
fn gen_from_str(_writer: &mut File, _entries: &[(String, String)]) {}

#[allow(unused)]
#[cfg(not(feature = "named_gradients"))]
pub fn build_gradients(_writer: &mut File) {}
<commit_msg>Add the license to the documentation of the const gradients<commit_after>use std::fs::File;

pub fn build() {
    use std::path::Path;

    let out_dir = ::std::env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("named.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named.rs");
    build_colors(&mut writer);
    let dest_path = Path::new(&out_dir).join("named_gradients.rs");
    let mut writer = File::create(dest_path).expect("couldn't create named_gradients.rs");
    build_gradients(&mut writer);
}

#[cfg(feature = "named")]
pub fn build_colors(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader =
        BufReader::new(File::open("build/svg_colors.txt").expect("could not open svg_colors.txt"));
    let mut entries = vec![];

    for line in reader.lines() {
        let line = line.unwrap();
        let mut parts = line.split('\t');
        let name = parts.next().expect("couldn't get the color name");
        let mut rgb = parts
            .next()
            .unwrap_or_else(|| panic!("couldn't get color for {}", name))
            .split(", ");
        let red: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get red for {}", name));
        let green: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get green for {}", name));
        let blue: u8 = rgb
            .next()
            .and_then(|r| r.trim().parse().ok())
            .unwrap_or_else(|| panic!("couldn't get blue for {}", name));

        writeln!(writer, "\n///

", name).unwrap();
        writeln!(writer, "pub const {}: crate::rgb::Srgb<u8> = crate::rgb::Srgb {{ red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData }};", name.to_uppercase(), red, green, blue).unwrap();

        entries.push((name.to_owned(), name.to_uppercase()));
    }

    gen_from_str(writer, &entries)
}

#[cfg(feature = "named_gradients")]
pub fn build_gradients(writer: &mut File) {
    use std::io::{BufRead, BufReader, Write};

    let reader =
        BufReader::new(File::open("build/svg_gradients_mpl.txt").expect("could not open svg_gradients_mpl.txt"));

    let mut line_iter = reader.lines();
    while let Some(Ok(line)) = line_iter.next(){
        //empty lines are allowed
        if line.is_empty() {continue;}
        let mut parts = line.split_whitespace();
        //every line should have the same info: name type number_of_colors [\n red green blue]^number_of_colors
        let name = parts.next().expect("couldn't get the color name");
        let color_type = parts.next().expect("couldn't get the type of the colors");
        //we assume that color_type is a rgb type
        let color_type = format!("crate::rgb::{}", color_type);
        let number_of_colors : usize = parts.next().expect("couldn't get the number of colors")
            .parse().unwrap_or_else(|_| panic!("couldn't parse the number of colors for color {}", name));
        writeln!(writer, "/// New matplotlib colormap by Nathaniel J. Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.").unwrap();
        writeln!(writer, "/// This gradient is perfectly perceptually-uniform, both in regular form and also when converted to black-and-white.").unwrap();
        writeln!(writer, "/// The colormap is released under the CC0 license public domain dedication.").unwrap();
        write!(writer,
            "pub const {0}: crate::gradient::Gradient<{1}, [(f32,{1});{2}]> = crate::gradient::Gradient([",
            name.to_uppercase(), color_type, number_of_colors).unwrap();
        for i in 0..number_of_colors {
            let color = line_iter
                .next()
                .unwrap_or_else(|| panic!("less lines than stated colors in gradient {}", name))
                .unwrap_or_else(|_| panic!("couldn't read the {}th line of color {}", i, name));
            let mut rgb = color.split(",");
            let red: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th red-value for {}", i, name));
            let green: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th green-value for {}", i, name));
            let blue: f32 = rgb
                .next()
                .and_then(|r| r.trim().parse().ok())
                .unwrap_or_else(|| panic!("couldn't get the {}th blue-value for {}", i, name));
            write!(writer, "({:.10},{}{{red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData}}),", (i as f32/number_of_colors as f32), color_type, red, green, blue).unwrap();
        }
        write!(writer, "]);\n").unwrap();
    }
}

#[cfg(feature = "named_from_str")]
fn gen_from_str(writer: &mut File, entries: &[(String, String)]) {
    use std::io::Write;

    let mut map = ::phf_codegen::Map::new();
    for &(ref key, ref value) in entries {
        map.entry(&**key, value);
    }
    write!(
        writer,
        "static COLORS: ::phf::Map<&'static str, crate::rgb::Srgb<u8>> = {};",
        map.build()
    )
    .unwrap();
}

#[cfg(not(feature = "named"))]
pub fn build_colors(_writer: &mut File) {}

#[allow(unused)]
#[cfg(not(feature = "named_from_str"))]
fn gen_from_str(_writer: &mut File, _entries: &[(String, String)]) {}

#[allow(unused)]
#[cfg(not(feature = "named_gradients"))]
pub fn build_gradients(_writer: &mut File) {}
<|endoftext|>


<commit_before>extern crate x11;
extern crate libc;

use std::ffi;
use std::process::Command;
use std::boxed::Box;

use x11::xlib;
use super::WindowManager;
use super::workspace::Workspaces;
use super::layout;

#[derive(Hash, Eq, PartialEq, Debug)]
pub struct KeyBind {
    pub key: u64,
    pub mask: u32,
}

impl KeyBind {
    pub fn build(mod_key: u32, tokens: &[&str]) -> KeyBind {
        let mut mask = 0;
        let mut sym = 0;
        for key in tokens {
            match *key {
                "$mod" => mask = mask | mod_key,
                "Shift" => mask = mask | xlib::ShiftMask,
                "Ctrl" => mask = mask | xlib::ControlMask,
                "Mod1" => mask = mask | xlib::Mod1Mask,
                "Mod2" => mask = mask | xlib::Mod2Mask,
                "Mod3" => mask = mask | xlib::Mod3Mask,
                "Mod4" => mask = mask | xlib::Mod4Mask,
                "Mod5" => mask = mask | xlib::Mod5Mask,
                _ => {
                    let tmp = ffi::CString::new(*key).unwrap();
                    unsafe{
                        sym = xlib::XStringToKeysym(tmp.as_ptr());
                    }
                }
            }
        }

        println!("bind {} {}", mask, sym);
        KeyBind {
            mask: mask,
            key: sym
        }
    }
}

pub trait Handler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int);
}

pub struct ExecHandler {
    pub cmd: Command
}

pub struct LayoutHandler {
    layout_type: layout::Type,
}

impl Handler for ExecHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        self.cmd.spawn();
    }
}

impl Handler for LayoutHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        let current = workspaces.current_workspace();
        let t = self.layout_type.clone();
        current.change_layout(t);
        current.config(display, screen_num);
    }
}

impl LayoutHandler {
    pub fn new(layout: layout::Type) -> LayoutHandler{
        LayoutHandler {
            layout_type: layout
        }
    }
}
impl ExecHandler {
    pub fn new(tokens: &[&str]) -> ExecHandler {
        let (name, args) = tokens.split_at(1);
        let mut cmd = Command::new(name[0]);

        for arg in args {
            println!("{}", arg);
            cmd.arg(arg);
        }

        let handler = ExecHandler {
            cmd: cmd,
        };
        handler
    }
}
<commit_msg>workspace handler<commit_after>extern crate x11;
extern crate libc;

use std::ffi;
use std::process::Command;
use std::boxed::Box;

use x11::xlib;
use super::WindowManager;
use super::workspace::Workspaces;
use super::layout;

#[derive(Hash, Eq, PartialEq, Debug)]
pub struct KeyBind {
    pub key: u64,
    pub mask: u32,
}

impl KeyBind {
    pub fn build(mod_key: u32, tokens: &[&str]) -> KeyBind {
        let mut mask = 0;
        let mut sym = 0;
        for key in tokens {
            match *key {
                "$mod" => mask = mask | mod_key,
                "Shift" => mask = mask | xlib::ShiftMask,
                "Ctrl" => mask = mask | xlib::ControlMask,
                "Mod1" => mask = mask | xlib::Mod1Mask,
                "Mod2" => mask = mask | xlib::Mod2Mask,
                "Mod3" => mask = mask | xlib::Mod3Mask,
                "Mod4" => mask = mask | xlib::Mod4Mask,
                "Mod5" => mask = mask | xlib::Mod5Mask,
                _ => {
                    let tmp = ffi::CString::new(*key).unwrap();
                    unsafe{
                        sym = xlib::XStringToKeysym(tmp.as_ptr());
                    }
                }
            }
        }

        println!("bind {} {}", mask, sym);
        KeyBind {
            mask: mask,
            key: sym
        }
    }
}

pub trait Handler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int);
}

pub struct ExecHandler {
    pub cmd: Command
}

pub struct LayoutHandler {
    layout_type: layout::Type,
}

/// switch to another workspace
pub struct WorkspaceHandler {
    key: char,
}

impl Handler for WorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        workspaces.switch_current(self.key);
    }
}

impl Handler for ExecHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        self.cmd.spawn();
    }
}

impl Handler for LayoutHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        let current = workspaces.current_workspace();
        let t = self.layout_type.clone();
        current.change_layout(t);
        current.config(display, screen_num);
    }
}

impl LayoutHandler {
    pub fn new(layout: layout::Type) -> LayoutHandler{
        LayoutHandler {
            layout_type: layout
        }
    }
}
impl ExecHandler {
    pub fn new(tokens: &[&str]) -> ExecHandler {
        let (name, args) = tokens.split_at(1);
        let mut cmd = Command::new(name[0]);

        for arg in args {
            println!("{}", arg);
            cmd.arg(arg);
        }

        let handler = ExecHandler {
            cmd: cmd,
        };
        handler
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate common;

use common::*;
use common::Projection::*;

use rand::{StdRng, SeedableRng, Rng};

#[cfg(debug_assertions)]
#[no_mangle]
pub fn new_state() -> State {
    println!("debug on");

    let seed: &[_] = &[42];
    let rng: StdRng = SeedableRng::from_seed(seed);

    make_state(rng)
}
#[cfg(not(debug_assertions))]
#[no_mangle]
pub fn new_state() -> State {
    let timestamp = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|dur| dur.as_secs())
        .unwrap_or(42);

    println!("{}", timestamp);
    let seed: &[_] = &[timestamp as usize];
    let rng: StdRng = SeedableRng::from_seed(seed);

    make_state(rng)
}

fn make_state(rng: StdRng) -> State {
    let mut state = State {
        rng,
        cam_x: 0.0,
        cam_y: 0.0,
        zoom: f32::powi(1.25, 8),
        board: HashMap::new(),
        mouse_pos: (400.0, 300.0),
        window_wh: (INITIAL_WINDOW_WIDTH as _, INITIAL_WINDOW_HEIGHT as _),
    };

    add_random_board_card(&mut state);

    state
}

#[no_mangle]
//returns true if quit requested
pub fn update_and_render(p: &Platform, state: &mut State, events: &mut Vec<Event>) -> bool {
    for event in events {
        if cfg!(debug_assertions) {
            match *event {
                Event::MouseMove(_) => {}
                _ => println!("{:?}", *event),
            }
        }

        match *event {
            Event::Quit |
            Event::KeyDown(Keycode::Escape) |
            Event::KeyDown(Keycode::F10) => {
                return true;
            }
            Event::KeyDown(Keycode::Space) => {
                add_random_board_card(state);
            }
            Event::KeyDown(Keycode::R) => {
                state.board.clear();
                add_random_board_card(state);
            }
            Event::KeyDown(Keycode::V) => {
                (p.set_verts)(get_vert_vecs());
            }
            Event::KeyDown(Keycode::Up) => {
                state.cam_y += 0.0625;
            }
            Event::KeyDown(Keycode::Down) => {
                state.cam_y -= 0.0625;
            }
            Event::KeyDown(Keycode::Right) => {
                state.cam_x += 0.0625;
            }
            Event::KeyDown(Keycode::Left) => {
                state.cam_x -= 0.0625;
            }
            Event::KeyDown(Keycode::Num0) => {
                state.cam_x = 0.0;
                state.cam_y = 0.0;
                state.zoom = 1.0;
            }
            Event::KeyDown(Keycode::W) => {
                state.zoom *= 1.25;
            }
            Event::KeyDown(Keycode::S) => {
                state.zoom /= 1.25;
            }
            Event::MouseMove((x, y)) => {
                state.mouse_pos = (x as f32, y as f32);
            }
            Event::WindowSize((w, h)) => {
                state.window_wh = (w as f32, h as f32);
            }
            _ => {}
        }
    }
    let aspect_ratio = state.window_wh.0 / state.window_wh.1;
    let view = {
        let near = 0.5;
        let far = 1024.0;

        let scale = state.zoom * near;
        let top = scale;
        let bottom = -top;
        let right = aspect_ratio * scale;
        let left = -right;

        let projection = get_projection(&ProjectionSpec {
            top,
            bottom,
            left,
            right,
            near,
            far,
            projection: Perspective,
            // projection: Orthographic,
        });

        let camera = [
            1.0,
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            0.0,
            state.cam_x,
            state.cam_y,
            0.0,
            1.0,
        ];

        mat4x4_mul(&camera, &projection)
    };

    for (grid_coords, &Space { card, ref pieces }) in state.board.iter() {

        let (x, y) = to_world_coords(*grid_coords);

        let angle = if (grid_coords.0 + grid_coords.1) % 2 == 0 {
            std::f32::consts::FRAC_PI_2
        } else {
            0.0
        };

        let world_matrix = [
            f32::cos(angle),
            -f32::sin(angle),
            0.0,
            0.0,
            f32::sin(angle),
            f32::cos(angle),
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            0.0,
            x,
            y,
            0.0,
            1.0,
        ];

        let card_matrix = mat4x4_mul(&world_matrix, &view);

        (p.draw_textured_poly_with_matrix)(card_matrix, CARD_POLY_INDEX, card.texture_spec());

        for (i, piece) in pieces.iter().enumerate() {
            let (x, y) = match i {
                0 => (0.35, 0.5),
                1 => (-0.35, 0.5),
                2 => (-0.35, -0.5),
                3 => (0.35, -0.5),
                _ => (0.0, 0.0),
            };

            let scale = piece_scale(piece);

            let piece_matrix = [
                scale * 5.0,
                0.0,
                0.0,
                0.0,
                0.0,
                scale * 5.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                x,
                y,
                0.0,
                1.0,
            ];

            (p.draw_textured_poly_with_matrix)(
                mat4x4_mul(&piece_matrix, &card_matrix),
                SQUARE_POLY_INDEX,
                piece_texture_spec(piece),
            );
        }

        let mouse_x = center(
            (TOOLTIP_TEXTURE_PIXEL_WIDTH / 2.0 + MOUSE_POINTER_SIZE +
                 state.mouse_pos.0) / state.window_wh.0,
        );
        let mouse_y = center(
            1.0 -
                ((TOOLTIP_TEXTURE_PIXEL_HEIGHT + state.mouse_pos.1) / state.window_wh.1),
        );
        let mouse_matrix = [
            0.05 * aspect_ratio,
            0.0,
            0.0,
            0.0,
            0.0,
            0.05,
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            0.0,
            mouse_x,
            mouse_y,
            0.0,
            1.0,
        ];

        let piece_colour = PieceColour::Blue;

        (p.draw_textured_poly_with_matrix)(mouse_matrix, 2, (
            3.0 * CARD_TEXTURE_WIDTH,
            4.0 * CARD_TEXTURE_HEIGHT +
                (f32::from(piece_colour) *
                     TOOLTIP_TEXTURE_HEIGHT_OFFSET),
            TOOLTIP_TEXTURE_WIDTH,
            TOOLTIP_TEXTURE_HEIGHT,
            0,
        ));
    }

    false
}

//map [0,1] to [-1,1]
fn center(x: f32) -> f32 {
    x * 2.0 - 1.0
}

//TODO: Is there a way to query for this rather than using this guess?
const MOUSE_POINTER_SIZE: f32 = 16.0;

const LARGEST_PIECE_TEXTURE_SIZE: f32 = 65.0 / T_S;

fn piece_scale(piece: &Piece) -> f32 {
    match piece.pips {
        Pips::One => 33.0 / T_S,
        Pips::Two => 49.0 / T_S,
        Pips::Three => LARGEST_PIECE_TEXTURE_SIZE,
    }
}

fn piece_texture_spec(piece: &Piece) -> TextureSpec {
    let size = piece_scale(piece);

    let (x, y) = match piece.pips {
        Pips::One => (114.0 / T_S, 792.0 / T_S),
        Pips::Two => (65.0 / T_S, 776.0 / T_S),
        Pips::Three => (0.0, 760.0 / T_S),
    };

    let colour_offset = LARGEST_PIECE_TEXTURE_SIZE *
        match piece.colour {
            PieceColour::Red => 0.0,
            PieceColour::Yellow => 1.0,
            PieceColour::Green => 2.0,
            PieceColour::Blue => 3.0,
        };

    (x, y + colour_offset, size, size, 0)
}

fn to_world_coords((grid_x, grid_y): (i8, i8)) -> (f32, f32) {
    (grid_x as f32 * 2.0, grid_y as f32 * 2.0)
}

fn add_random_board_card(state: &mut State) {
    state.board.insert(
        (state.rng.gen_range(-4, 4), state.rng.gen_range(-4, 4)),
        state.rng.gen(),
    );
}

const CARD_POLY_INDEX: usize = 0;
const SQUARE_POLY_INDEX: usize = 1;

const CARD_RATIO: f32 = CARD_TEXTURE_PIXEL_WIDTH / CARD_TEXTURE_PIXEL_HEIGHT;
const TOOLTIP_RATIO: f32 = TOOLTIP_TEXTURE_PIXEL_WIDTH / TOOLTIP_TEXTURE_PIXEL_HEIGHT;

//These are the verticies of the polygons which can be drawn.
//The index refers to the index of the inner vector within the outer vecton.
#[cfg_attr(rustfmt, rustfmt_skip)]
#[no_mangle]
pub fn get_vert_vecs() -> Vec<Vec<f32>> {
    vec![
        //Card
        vec![
            -CARD_RATIO, 1.0,
            -CARD_RATIO, -1.0,
            CARD_RATIO, -1.0,
            CARD_RATIO, 1.0,
        ],
        //Square
        vec![
            -1.0, 1.0,
            -1.0, -1.0,
            1.0, -1.0,
            1.0, 1.0,
        ],
        //Tooltip
        vec![
            -TOOLTIP_RATIO/2.0, 1.0,
            -TOOLTIP_RATIO/2.0, -1.0,
            TOOLTIP_RATIO/2.0, -1.0,
            TOOLTIP_RATIO/2.0, 1.0,
        ],
    ]
}
<commit_msg>make tooltip aspect ratio stay constant<commit_after>extern crate rand;
extern crate common;

use common::*;
use common::Projection::*;

use rand::{StdRng, SeedableRng, Rng};

#[cfg(debug_assertions)]
#[no_mangle]
pub fn new_state() -> State {
    println!("debug on");

    let seed: &[_] = &[42];
    let rng: StdRng = SeedableRng::from_seed(seed);

    make_state(rng)
}
#[cfg(not(debug_assertions))]
#[no_mangle]
pub fn new_state() -> State {
    let timestamp = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|dur| dur.as_secs())
        .unwrap_or(42);

    println!("{}", timestamp);
    let seed: &[_] = &[timestamp as usize];
    let rng: StdRng = SeedableRng::from_seed(seed);

    make_state(rng)
}

fn make_state(rng: StdRng) -> State {
    let mut state = State {
        rng,
        cam_x: 0.0,
        cam_y: 0.0,
        zoom: f32::powi(1.25, 8),
        board: HashMap::new(),
        mouse_pos: (400.0, 300.0),
        window_wh: (INITIAL_WINDOW_WIDTH as _, INITIAL_WINDOW_HEIGHT as _),
    };

    add_random_board_card(&mut state);

    state
}

#[no_mangle]
//returns true if quit requested
pub fn update_and_render(p: &Platform, state: &mut State, events: &mut Vec<Event>) -> bool {
    for event in events {
        if cfg!(debug_assertions) {
            match *event {
                Event::MouseMove(_) => {}
                _ => println!("{:?}", *event),
            }
        }

        match *event {
            Event::Quit |
            Event::KeyDown(Keycode::Escape) |
            Event::KeyDown(Keycode::F10) => {
                return true;
            }
            Event::KeyDown(Keycode::Space) => {
                add_random_board_card(state);
            }
            Event::KeyDown(Keycode::R) => {
                state.board.clear();
                add_random_board_card(state);
            }
            Event::KeyDown(Keycode::V) => {
                (p.set_verts)(get_vert_vecs());
            }
            Event::KeyDown(Keycode::Up) => {
                state.cam_y += 0.0625;
            }
            Event::KeyDown(Keycode::Down) => {
                state.cam_y -= 0.0625;
            }
            Event::KeyDown(Keycode::Right) => {
                state.cam_x += 0.0625;
            }
            Event::KeyDown(Keycode::Left) => {
                state.cam_x -= 0.0625;
            }
            Event::KeyDown(Keycode::Num0) => {
                state.cam_x = 0.0;
                state.cam_y = 0.0;
                state.zoom = 1.0;
            }
            Event::KeyDown(Keycode::W) => {
                state.zoom *= 1.25;
            }
            Event::KeyDown(Keycode::S) => {
                state.zoom /= 1.25;
            }
            Event::MouseMove((x, y)) => {
                state.mouse_pos = (x as f32, y as f32);
            }
            Event::WindowSize((w, h)) => {
                state.window_wh = (w as f32, h as f32);
                println!("{}", state.window_wh.0 / state.window_wh.1);
            }
            _ => {}
        }
    }
    let aspect_ratio = state.window_wh.0 / state.window_wh.1;
    let view = {
        let near = 0.5;
        let far = 1024.0;

        let scale = state.zoom * near;
        let top = scale;
        let bottom = -top;
        let right = aspect_ratio * scale;
        let left = -right;

        let projection = get_projection(&ProjectionSpec {
            top,
            bottom,
            left,
            right,
            near,
            far,
            projection: Perspective,
            // projection: Orthographic,
        });

        let camera = [
            1.0,
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            0.0,
            state.cam_x,
            state.cam_y,
            0.0,
            1.0,
        ];

        mat4x4_mul(&camera, &projection)
    };

    for (grid_coords, &Space { card, ref pieces }) in state.board.iter() {

        let (x, y) = to_world_coords(*grid_coords);

        let angle = if (grid_coords.0 + grid_coords.1) % 2 == 0 {
            std::f32::consts::FRAC_PI_2
        } else {
            0.0
        };

        let world_matrix = [
            f32::cos(angle),
            -f32::sin(angle),
            0.0,
            0.0,
            f32::sin(angle),
            f32::cos(angle),
            0.0,
            0.0,
            0.0,
            0.0,
            1.0,
            0.0,
            x,
            y,
            0.0,
            1.0,
        ];

        let card_matrix = mat4x4_mul(&world_matrix, &view);

        (p.draw_textured_poly_with_matrix)(card_matrix, CARD_POLY_INDEX, card.texture_spec());

        for (i, piece) in pieces.iter().enumerate() {
            let (x, y) = match i {
                0 => (0.35, 0.5),
                1 => (-0.35, 0.5),
                2 => (-0.35, -0.5),
                3 => (0.35, -0.5),
                _ => (0.0, 0.0),
            };

            let scale = piece_scale(piece);

            let piece_matrix = [
                scale * 5.0,
                0.0,
                0.0,
                0.0,
                0.0,
                scale * 5.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                x,
                y,
                0.0,
                1.0,
            ];

            (p.draw_textured_poly_with_matrix)(
                mat4x4_mul(&piece_matrix, &card_matrix),
                SQUARE_POLY_INDEX,
                piece_texture_spec(piece),
            );
        }
        {
            let near = 0.5;
            let far = 1024.0;

            let scale = 8.0;
            let top = scale;
            let bottom = -top;
            let right = aspect_ratio * scale;
            let left = -right;
            let view = {

                let projection = get_projection(&ProjectionSpec {
                    top,
                    bottom,
                    left,
                    right,
                    near,
                    far,
                    // projection: Perspective,
                    projection: Orthographic,
                });

                let camera = [
                    1.0,
                    0.0,
                    0.0,
                    0.0,
                    0.0,
                    1.0,
                    0.0,
                    0.0,
                    0.0,
                    0.0,
                    1.0,
                    0.0,
                    state.cam_x,
                    state.cam_y,
                    0.0,
                    1.0,
                ];

                mat4x4_mul(&camera, &projection)
            };

            let mouse_x = center((state.mouse_pos.0) / state.window_wh.0);
            let mouse_y = -center(((state.mouse_pos.1) / state.window_wh.1));

            println!("{:?}", (mouse_x, mouse_y));

            let mouse_camera_matrix = [
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                0.0,
                0.0,
                1.0,
                0.0,
                mouse_x * (right - left),
                mouse_y * (top - bottom),
                0.0,
                1.0,
            ];

            let mouse_matrix = mat4x4_mul(&mouse_camera_matrix, &view);
            // let mouse_matrix = mouse_camera_matrix;

            let piece_colour = PieceColour::Blue;

            (p.draw_textured_poly_with_matrix)(mouse_matrix, 2, (
                3.0 * CARD_TEXTURE_WIDTH,
                4.0 * CARD_TEXTURE_HEIGHT +
                    (f32::from(piece_colour) *
                         TOOLTIP_TEXTURE_HEIGHT_OFFSET),
                TOOLTIP_TEXTURE_WIDTH,
                TOOLTIP_TEXTURE_HEIGHT,
                0,
            ));
        }
    }

    false
}

//map [0,1] to [-1,1]
fn center(x: f32) -> f32 {
    x * 2.0 - 1.0
}

//TODO: Is there a way to query for this rather than using this guess?
const MOUSE_POINTER_SIZE: f32 = 16.0;

const LARGEST_PIECE_TEXTURE_SIZE: f32 = 65.0 / T_S;

fn piece_scale(piece: &Piece) -> f32 {
    match piece.pips {
        Pips::One => 33.0 / T_S,
        Pips::Two => 49.0 / T_S,
        Pips::Three => LARGEST_PIECE_TEXTURE_SIZE,
    }
}

fn piece_texture_spec(piece: &Piece) -> TextureSpec {
    let size = piece_scale(piece);

    let (x, y) = match piece.pips {
        Pips::One => (114.0 / T_S, 792.0 / T_S),
        Pips::Two => (65.0 / T_S, 776.0 / T_S),
        Pips::Three => (0.0, 760.0 / T_S),
    };

    let colour_offset = LARGEST_PIECE_TEXTURE_SIZE *
        match piece.colour {
            PieceColour::Red => 0.0,
            PieceColour::Yellow => 1.0,
            PieceColour::Green => 2.0,
            PieceColour::Blue => 3.0,
        };

    (x, y + colour_offset, size, size, 0)
}

fn to_world_coords((grid_x, grid_y): (i8, i8)) -> (f32, f32) {
    (grid_x as f32 * 2.0, grid_y as f32 * 2.0)
}

fn add_random_board_card(state: &mut State) {
    state.board.insert(
        (state.rng.gen_range(-4, 4), state.rng.gen_range(-4, 4)),
        state.rng.gen(),
    );
}

const CARD_POLY_INDEX: usize = 0;
const SQUARE_POLY_INDEX: usize = 1;

const CARD_RATIO: f32 = CARD_TEXTURE_PIXEL_WIDTH / CARD_TEXTURE_PIXEL_HEIGHT;
const TOOLTIP_RATIO: f32 = TOOLTIP_TEXTURE_PIXEL_WIDTH / TOOLTIP_TEXTURE_PIXEL_HEIGHT;

//These are the verticies of the polygons which can be drawn.
//The index refers to the index of the inner vector within the outer vecton.
#[cfg_attr(rustfmt, rustfmt_skip)]
#[no_mangle]
pub fn get_vert_vecs() -> Vec<Vec<f32>> {
    vec![
        //Card
        vec![
            -CARD_RATIO, 1.0,
            -CARD_RATIO, -1.0,
            CARD_RATIO, -1.0,
            CARD_RATIO, 1.0,
        ],
        //Square
        vec![
            -1.0, 1.0,
            -1.0, -1.0,
            1.0, -1.0,
            1.0, 1.0,
        ],
        //Tooltip
        vec![
            -TOOLTIP_RATIO, 1.0,
            -TOOLTIP_RATIO, -1.0,
            TOOLTIP_RATIO, -1.0,
            TOOLTIP_RATIO, 1.0,
        ],
    ]
}
<|endoftext|>