<commit_before>use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use conduit::Response;
use diesel::result::Error as DieselError;

use crate::util::json_response;

#[derive(Serialize)]
struct StringError {
    detail: String,
}
#[derive(Serialize)]
struct Bad {
    errors: Vec<StringError>,
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    fn description(&self) -> &str;
    fn cause(&self) -> Option<&(dyn AppError)> {
        None
    }

    /// Generate an HTTP response for the error
    fn response(&self) -> Option<Response>;

    /// Fallback logic for generating a cargo friendly response
    ///
    /// This behavior is deprecated and no new calls or impls should be added.
    fn fallback_response(&self) -> Option<Response> {
        if self.fallback_with_description_as_bad_200() {
            Some(json_response(&Bad {
                errors: vec![StringError {
                    detail: self.description().to_string(),
                }],
            }))
        } else {
            self.cause().and_then(AppError::response)
        }
    }

    /// Determines if the `fallback_response` method should send the description as a status 200
    /// error to cargo, or send the cause response (if applicable).
    ///
    /// This is only to be used by the `fallback_response` method.  If your error type impls
    /// `response`, then there is no need to impl this method.
    fn fallback_with_description_as_bad_200(&self) -> bool {
        false
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    pub fn from_std_error(err: Box<dyn Error + Send>) -> Box<dyn AppError> {
        Self::try_convert(&*err).unwrap_or_else(|| internal(&err))
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(Box::new(NotFound)),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn description(&self) -> &str {
        (**self).description()
    }
    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }
    fn fallback_with_description_as_bad_200(&self) -> bool {
        (**self).fallback_with_description_as_bad_200()
    }
    fn response(&self) -> Option<Response> {
        (**self).response()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, F> ChainError<T> for F
where
    F: FnOnce() -> AppResult<T>,
{
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        self().chain_error(callback)
    }
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| {
            Box::new(ChainedError {
                error: callback(),
                cause: Box::new(err),
            }) as Box<dyn AppError>
        })
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn description(&self) -> &str {
        self.error.description()
    }
    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
    fn response(&self) -> Option<Response> {
        self.error.response()
    }
    fn fallback_with_description_as_bad_200(&self) -> bool {
        self.error.fallback_with_description_as_bad_200()
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn description(&self) -> &str {
        Error::description(self)
    }
    fn response(&self) -> Option<Response> {
        self.fallback_response()
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        AppError::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Concrete errors

#[derive(Debug)]
struct ConcreteAppError {
    description: String,
    detail: Option<String>,
    cause: Option<Box<dyn AppError>>,
    cargo_err: bool,
}

impl fmt::Display for ConcreteAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        if let Some(ref s) = self.detail {
            write!(f, " ({})", s)?;
        }
        Ok(())
    }
}

impl AppError for ConcreteAppError {
    fn description(&self) -> &str {
        &self.description
    }
    fn cause(&self) -> Option<&dyn AppError> {
        self.cause.as_ref().map(|c| &**c)
    }
    fn response(&self) -> Option<Response> {
        self.fallback_response()
    }
    fn fallback_with_description_as_bad_200(&self) -> bool {
        self.cargo_err
    }
}

#[derive(Debug, Clone, Copy)]
pub struct NotFound;

impl AppError for NotFound {
    fn description(&self) -> &str {
        "not found"
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: "Not Found".to_string(),
            }],
        });
        response.status = (404, "Not Found");
        Some(response)
    }
}

impl fmt::Display for NotFound {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Not Found".fmt(f)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Unauthorized;

impl AppError for Unauthorized {
    fn description(&self) -> &str {
        "unauthorized"
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: "must be logged in to perform that action".to_string(),
            }],
        });
        response.status = (403, "Forbidden");
        Some(response)
    }
}

impl fmt::Display for Unauthorized {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "must be logged in to perform that action".fmt(f)
    }
}

#[derive(Debug)]
struct BadRequest(String);

impl AppError for BadRequest {
    fn description(&self) -> &str {
        self.0.as_ref()
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: self.0.clone(),
            }],
        });
        response.status = (400, "Bad Request");
        Some(response)
    }
}

impl fmt::Display for BadRequest {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(ConcreteAppError {
        description: error.to_string(),
        detail: None,
        cause: None,
        cargo_err: false,
    })
}

pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(ConcreteAppError {
        description: error.to_string(),
        detail: None,
        cause: None,
        cargo_err: true,
    })
}

/// This is intended to be used for errors being sent back to the Ember
/// frontend, not to cargo as cargo does not handle non-200 response codes well
/// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
/// non-200 response codes for its stores to work properly.
///
/// Since this is going back to the UI these errors are treated the same as
/// `cargo_err` errors, other than the HTTP status code.
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(BadRequest(error.to_string()))
}

#[derive(Debug)]
pub struct AppErrToStdErr(pub Box<dyn AppError>);

impl Error for AppErrToStdErr {
    fn description(&self) -> &str {
        self.0.description()
    }
}

impl fmt::Display for AppErrToStdErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)?;

        let mut err = &*self.0;
        while let Some(cause) = err.cause() {
            err = cause;
            write!(f, "\nCaused by: {}", err)?;
        }

        Ok(())
    }
}

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

pub(crate) fn std_error_no_send(e: Box<dyn AppError>) -> Box<dyn Error> {
    Box::new(AppErrToStdErr(e))
}

#[derive(Debug, Clone, Copy)]
pub struct ReadOnlyMode;

impl AppError for ReadOnlyMode {
    fn description(&self) -> &str {
        "tried to write in read only mode"
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: "Crates.io is currently in read-only mode for maintenance. \
                         Please try again later."
                    .to_string(),
            }],
        });
        response.status = (503, "Service Unavailable");
        Some(response)
    }
}

impl fmt::Display for ReadOnlyMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Tried to write in read only mode".fmt(f)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct TooManyRequests {
    pub retry_after: NaiveDateTime,
}

impl AppError for TooManyRequests {
    fn description(&self) -> &str {
        "too many requests"
    }

    fn response(&self) -> Option<Response> {
        const HTTP_DATE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT";
        let retry_after = self.retry_after.format(HTTP_DATE_FORMAT);

        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: format!(
                    "You have published too many crates in a \
                     short period of time. Please try again after {} or email \
                     help@crates.io to have your limit increased.",
                    retry_after
                ),
            }],
        });
        response.status = (429, "TOO MANY REQUESTS");
        response
            .headers
            .insert("Retry-After".into(), vec![retry_after.to_string()]);
        Some(response)
    }
}

impl fmt::Display for TooManyRequests {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Too many requests".fmt(f)
    }
}
<commit_msg>Remove some unused fields from ConcreteAppError<commit_after>use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use conduit::Response;
use diesel::result::Error as DieselError;

use crate::util::json_response;

#[derive(Serialize)]
struct StringError {
    detail: String,
}
#[derive(Serialize)]
struct Bad {
    errors: Vec<StringError>,
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    fn description(&self) -> &str;
    fn cause(&self) -> Option<&(dyn AppError)> {
        None
    }

    /// Generate an HTTP response for the error
    fn response(&self) -> Option<Response>;

    /// Fallback logic for generating a cargo friendly response
    ///
    /// This behavior is deprecated and no new calls or impls should be added.
    fn fallback_response(&self) -> Option<Response> {
        if self.fallback_with_description_as_bad_200() {
            Some(json_response(&Bad {
                errors: vec![StringError {
                    detail: self.description().to_string(),
                }],
            }))
        } else {
            self.cause().and_then(AppError::response)
        }
    }

    /// Determines if the `fallback_response` method should send the description as a status 200
    /// error to cargo, or send the cause response (if applicable).
    ///
    /// This is only to be used by the `fallback_response` method.  If your error type impls
    /// `response`, then there is no need to impl this method.
    fn fallback_with_description_as_bad_200(&self) -> bool {
        false
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    pub fn from_std_error(err: Box<dyn Error + Send>) -> Box<dyn AppError> {
        Self::try_convert(&*err).unwrap_or_else(|| internal(&err))
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(Box::new(NotFound)),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn description(&self) -> &str {
        (**self).description()
    }
    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }
    fn fallback_with_description_as_bad_200(&self) -> bool {
        (**self).fallback_with_description_as_bad_200()
    }
    fn response(&self) -> Option<Response> {
        (**self).response()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, F> ChainError<T> for F
where
    F: FnOnce() -> AppResult<T>,
{
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        self().chain_error(callback)
    }
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| {
            Box::new(ChainedError {
                error: callback(),
                cause: Box::new(err),
            }) as Box<dyn AppError>
        })
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn description(&self) -> &str {
        self.error.description()
    }
    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
    fn response(&self) -> Option<Response> {
        self.error.response()
    }
    fn fallback_with_description_as_bad_200(&self) -> bool {
        self.error.fallback_with_description_as_bad_200()
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn description(&self) -> &str {
        Error::description(self)
    }
    fn response(&self) -> Option<Response> {
        self.fallback_response()
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        AppError::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Concrete errors

#[derive(Debug)]
struct ConcreteAppError {
    description: String,
    cargo_err: bool,
}

impl fmt::Display for ConcreteAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for ConcreteAppError {
    fn description(&self) -> &str {
        &self.description
    }
    fn cause(&self) -> Option<&dyn AppError> {
        None
    }
    fn response(&self) -> Option<Response> {
        self.fallback_response()
    }
    fn fallback_with_description_as_bad_200(&self) -> bool {
        self.cargo_err
    }
}

#[derive(Debug, Clone, Copy)]
pub struct NotFound;

impl AppError for NotFound {
    fn description(&self) -> &str {
        "not found"
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: "Not Found".to_string(),
            }],
        });
        response.status = (404, "Not Found");
        Some(response)
    }
}

impl fmt::Display for NotFound {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Not Found".fmt(f)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Unauthorized;

impl AppError for Unauthorized {
    fn description(&self) -> &str {
        "unauthorized"
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: "must be logged in to perform that action".to_string(),
            }],
        });
        response.status = (403, "Forbidden");
        Some(response)
    }
}

impl fmt::Display for Unauthorized {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "must be logged in to perform that action".fmt(f)
    }
}

#[derive(Debug)]
struct BadRequest(String);

impl AppError for BadRequest {
    fn description(&self) -> &str {
        self.0.as_ref()
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: self.0.clone(),
            }],
        });
        response.status = (400, "Bad Request");
        Some(response)
    }
}

impl fmt::Display for BadRequest {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(ConcreteAppError {
        description: error.to_string(),
        cargo_err: false,
    })
}

pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(ConcreteAppError {
        description: error.to_string(),
        cargo_err: true,
    })
}

/// This is intended to be used for errors being sent back to the Ember
/// frontend, not to cargo as cargo does not handle non-200 response codes well
/// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
/// non-200 response codes for its stores to work properly.
///
/// Since this is going back to the UI these errors are treated the same as
/// `cargo_err` errors, other than the HTTP status code.
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(BadRequest(error.to_string()))
}

#[derive(Debug)]
pub struct AppErrToStdErr(pub Box<dyn AppError>);

impl Error for AppErrToStdErr {
    fn description(&self) -> &str {
        self.0.description()
    }
}

impl fmt::Display for AppErrToStdErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)?;

        let mut err = &*self.0;
        while let Some(cause) = err.cause() {
            err = cause;
            write!(f, "\nCaused by: {}", err)?;
        }

        Ok(())
    }
}

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

pub(crate) fn std_error_no_send(e: Box<dyn AppError>) -> Box<dyn Error> {
    Box::new(AppErrToStdErr(e))
}

#[derive(Debug, Clone, Copy)]
pub struct ReadOnlyMode;

impl AppError for ReadOnlyMode {
    fn description(&self) -> &str {
        "tried to write in read only mode"
    }

    fn response(&self) -> Option<Response> {
        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: "Crates.io is currently in read-only mode for maintenance. \
                         Please try again later."
                    .to_string(),
            }],
        });
        response.status = (503, "Service Unavailable");
        Some(response)
    }
}

impl fmt::Display for ReadOnlyMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Tried to write in read only mode".fmt(f)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct TooManyRequests {
    pub retry_after: NaiveDateTime,
}

impl AppError for TooManyRequests {
    fn description(&self) -> &str {
        "too many requests"
    }

    fn response(&self) -> Option<Response> {
        const HTTP_DATE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT";
        let retry_after = self.retry_after.format(HTTP_DATE_FORMAT);

        let mut response = json_response(&Bad {
            errors: vec![StringError {
                detail: format!(
                    "You have published too many crates in a \
                     short period of time. Please try again after {} or email \
                     help@crates.io to have your limit increased.",
                    retry_after
                ),
            }],
        });
        response.status = (429, "TOO MANY REQUESTS");
        response
            .headers
            .insert("Retry-After".into(), vec![retry_after.to_string()]);
        Some(response)
    }
}

impl fmt::Display for TooManyRequests {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "Too many requests".fmt(f)
    }
}
<|endoftext|>


<commit_before>use oppai_field::field::{euclidean, wave_diag, Field, Pos};
use oppai_field::player::Player;
use std::{
  collections::HashSet,
  ops::Index,
  sync::atomic::{AtomicBool, Ordering},
};

#[derive(Debug, Clone)]
struct Trajectory {
  points: Vec<Pos>,
  hash: u64,
}

impl Trajectory {
  pub fn new(points: Vec<Pos>, hash: u64) -> Trajectory {
    Trajectory { points, hash }
  }

  pub fn points(&self) -> &Vec<Pos> {
    &self.points
  }

  pub fn hash(&self) -> u64 {
    self.hash
  }

  pub fn len(&self) -> usize {
    self.points.len()
  }
}

pub struct TrajectoriesPruning {
  rebuild_trajectories: bool,
  cur_trajectories: Vec<Trajectory>,
  enemy_trajectories: Vec<Trajectory>,
  moves: Vec<Pos>,
}

impl TrajectoriesPruning {
  fn add_trajectory(field: &Field, trajectories: &mut Vec<Trajectory>, points: &[Pos], player: Player) {
    for &pos in points {
      if !field.cell(pos).is_bound() || field.number_near_groups(pos, player) < 2 {
        return;
      }
    }
    let zobrist = field.zobrist();
    let mut hash = 0u64;
    for &pos in points {
      hash ^= zobrist.get_hash(pos);
    }
    for trajectory in trajectories.iter() {
      if trajectory.hash() == hash {
        return;
      }
    }
    let trajectory = Trajectory::new(points.to_vec(), hash);
    trajectories.push(trajectory);
  }

  fn next_moves(
    field: &Field,
    start_pos: Pos,
    player: Player,
    empty_board: &mut Vec<u32>,
    marks: &mut Vec<Pos>,
  ) -> Vec<Pos> {
    let mut moves = Vec::new();
    wave_diag(field.width(), start_pos, |pos| {
      if empty_board[pos] != 0 {
        return false;
      }
      let cell = field.cell(pos);
      if cell.is_players_point(player) {
        empty_board[pos] = 1;
        marks.push(pos);
        true
      } else {
        if cell.is_putting_allowed() && !cell.is_players_empty_base(player) {
          empty_board[pos] = 1;
          moves.push(pos);
        }
        false
      }
    });
    for &pos in &moves {
      empty_board[pos] = 0;
    }
    moves
  }

  fn build_trajectories_rec(
    field: &mut Field,
    trajectories: &mut Vec<Trajectory>,
    player: Player,
    cur_depth: u32,
    depth: u32,
    empty_board: &mut Vec<u32>,
    last_pos: Pos,
    moves: Vec<Pos>,
    should_stop: &AtomicBool,
  ) {
    for pos in moves {
      if should_stop.load(Ordering::Relaxed) {
        break;
      }
      if field.number_near_points(pos, player) >= 3 {
        continue;
      }
      let cell = field.cell(pos);
      if cell.is_players_empty_base(player.next()) {
        field.put_point(pos, player);
        if field.get_delta_score(player) > 0 {
          TrajectoriesPruning::add_trajectory(
            field,
            trajectories,
            field
              .points_seq()
              .index(field.moves_count() - cur_depth as usize..field.moves_count()),
            player,
          );
        }
        field.undo();
      } else {
        field.put_point(pos, player);
        if field.get_delta_score(player) > 0 {
          TrajectoriesPruning::add_trajectory(
            field,
            trajectories,
            field
              .points_seq()
              .index(field.moves_count() - cur_depth as usize..field.moves_count()),
            player,
          );
        } else if depth > 0 {
          let mut marks = Vec::new();
          let mut next_moves = TrajectoriesPruning::next_moves(field, pos, player, empty_board, &mut marks);
          if last_pos != 0 {
            next_moves.retain(|&next_pos| euclidean(field.width(), last_pos, next_pos) > 2);
          }
          TrajectoriesPruning::build_trajectories_rec(
            field,
            trajectories,
            player,
            cur_depth + 1,
            depth - 1,
            empty_board,
            pos,
            next_moves,
            should_stop,
          );
          for mark_pos in marks {
            empty_board[mark_pos] = 0;
          }
        }
        field.undo();
      }
    }
  }

  fn build_trajectories(
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    should_stop: &AtomicBool,
  ) -> Vec<Trajectory> {
    let mut trajectories = Vec::new();

    if depth == 0 {
      return trajectories;
    }

    let mut marks = Vec::new();
    for pos in field.points_seq().clone() {
      if field.cell(pos).get_player() != player {
        continue;
      }

      if should_stop.load(Ordering::Relaxed) {
        break;
      }

      let moves = TrajectoriesPruning::next_moves(field, pos, player, empty_board, &mut marks);

      TrajectoriesPruning::build_trajectories_rec(
        field,
        &mut trajectories,
        player,
        1,
        depth - 1,
        empty_board,
        0,
        moves,
        should_stop,
      );
    }

    for pos in marks {
      empty_board[pos] = 0;
    }

    trajectories
  }

  fn project(trajectories: &[Trajectory], empty_board: &mut Vec<u32>) {
    for &pos in trajectories.iter().flat_map(|trajectory| trajectory.points().iter()) {
      empty_board[pos] += 1;
    }
  }

  fn project_length(trajectories: &[Trajectory], empty_board: &mut Vec<u32>) {
    for trajectory in trajectories {
      let len = trajectory.len() as u32;
      for &pos in trajectory.points() {
        if empty_board[pos] == 0 || empty_board[pos] > len {
          empty_board[pos] = len;
        }
      }
    }
  }

  fn deproject(trajectories: &[Trajectory], empty_board: &mut Vec<u32>) {
    for &pos in trajectories.iter().flat_map(|trajectory| trajectory.points().iter()) {
      empty_board[pos] = 0;
    }
  }

  fn exclude_unnecessary_trajectories(trajectories: &mut Vec<Trajectory>, empty_board: &mut Vec<u32>) -> bool {
    let mut need_exclude = false;
    trajectories.retain(|trajectory| {
      let single_count = trajectory.points().iter().filter(|&&pos| empty_board[pos] == 1).count();
      if single_count > 1 {
        for &pos in trajectory.points() {
          empty_board[pos] -= 1;
        }
        need_exclude = true;
        false
      } else {
        true
      }
    });
    need_exclude
  }

  fn calculate_moves(
    trajectories1: &mut Vec<Trajectory>,
    trajectories2: &mut Vec<Trajectory>,
    empty_board: &mut Vec<u32>,
  ) -> Vec<Pos> {
    TrajectoriesPruning::project(trajectories1, empty_board);
    TrajectoriesPruning::project(trajectories2, empty_board);
    while TrajectoriesPruning::exclude_unnecessary_trajectories(trajectories1, empty_board)
      || TrajectoriesPruning::exclude_unnecessary_trajectories(trajectories2, empty_board)
    {}
    let mut result_set = HashSet::new();
    for &pos in trajectories1
      .iter()
      .chain(trajectories2.iter())
      .flat_map(|trajectory| trajectory.points().iter())
    {
      result_set.insert(pos);
    }
    let mut result = result_set.into_iter().collect::<Vec<Pos>>();
    result.sort_unstable_by(|&pos1, &pos2| empty_board[pos2].cmp(&empty_board[pos1]));
    TrajectoriesPruning::deproject(trajectories1, empty_board);
    TrajectoriesPruning::deproject(trajectories2, empty_board);
    TrajectoriesPruning::project_length(trajectories1, empty_board);
    TrajectoriesPruning::project_length(trajectories2, empty_board);
    result.sort_by(|&pos1, &pos2| empty_board[pos1].cmp(&empty_board[pos2]));
    TrajectoriesPruning::deproject(trajectories1, empty_board);
    TrajectoriesPruning::deproject(trajectories2, empty_board);
    result
  }

  #[inline]
  pub fn empty(rebuild_trajectories: bool) -> TrajectoriesPruning {
    TrajectoriesPruning {
      rebuild_trajectories,
      cur_trajectories: Vec::with_capacity(0),
      enemy_trajectories: Vec::with_capacity(0),
      moves: Vec::with_capacity(0),
    }
  }

  pub fn new(
    rebuild_trajectories: bool,
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    should_stop: &AtomicBool,
  ) -> TrajectoriesPruning {
    if depth == 0 {
      return TrajectoriesPruning::empty(rebuild_trajectories);
    }
    let mut cur_trajectories =
      TrajectoriesPruning::build_trajectories(field, player, (depth + 1) / 2, empty_board, should_stop);
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(rebuild_trajectories);
    }
    let mut enemy_trajectories =
      TrajectoriesPruning::build_trajectories(field, player.next(), depth / 2, empty_board, should_stop);
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  fn last_pos_trajectory(field: &Field, player: Player, depth: u32, last_pos: Pos) -> Option<Trajectory> {
    let mut points = Vec::with_capacity(4);
    let mut hash = 0;
    for &pos in &field.directions(last_pos) {
      if field.cell(pos).is_putting_allowed() {
        let mut neighbors_count = 0;
        for &neighbor in &field.directions(pos) {
          if field.cell(neighbor).is_players_point(player) {
            neighbors_count += 1;
          }
        }
        if neighbors_count < 3 {
          points.push(pos);
          hash ^= field.zobrist().get_hash(pos);
        }
      } else if !field.cell(pos).is_players_point(player) {
        return None;
      }
    }
    if points.len() as u32 <= (depth + 1) / 2 {
      Some(Trajectory::new(points, hash))
    } else {
      None
    }
  }

  pub fn next(
    &self,
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    last_pos: Pos,
    should_stop: &AtomicBool,
  ) -> TrajectoriesPruning {
    if depth == 0 {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let mut cur_trajectories = if self.rebuild_trajectories {
      TrajectoriesPruning::build_trajectories(field, player, (depth + 1) / 2, empty_board, should_stop)
    } else {
      self
        .enemy_trajectories
        .iter()
        .filter(|trajectory| {
          trajectory
            .points()
            .iter()
            .all(|&pos| field.cell(pos).is_putting_allowed())
        })
        .cloned()
        .chain(TrajectoriesPruning::last_pos_trajectory(field, player, depth, last_pos).into_iter())
        .collect()
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let enemy_depth = depth / 2;
    let mut enemy_trajectories = if enemy_depth > 0 {
      self
        .cur_trajectories
        .iter()
        .filter_map(|trajectory| {
          let len = trajectory.len() as u32;
          let contains_pos = trajectory.points().contains(&last_pos);
          if (len <= enemy_depth || len == enemy_depth + 1 && contains_pos)
            && trajectory
              .points()
              .iter()
              .all(|&pos| field.cell(pos).is_putting_allowed() || pos == last_pos)
          {
            let new_trajectory = if contains_pos {
              if len == 1 {
                return None;
              }
              Trajectory::new(
                trajectory
                  .points
                  .iter()
                  .cloned()
                  .filter(|&pos| pos != last_pos)
                  .collect(),
                trajectory.hash() ^ field.zobrist().get_hash(last_pos),
              )
            } else {
              trajectory.clone()
            };
            Some(new_trajectory)
          } else {
            None
          }
        })
        .collect()
    } else {
      Vec::new()
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories: self.rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  pub fn dec_and_swap(&self, depth: u32, empty_board: &mut Vec<u32>, should_stop: &AtomicBool) -> TrajectoriesPruning {
    if depth == 0 {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let mut cur_trajectories = self.enemy_trajectories.clone();
    let enemy_depth = depth / 2;
    let mut enemy_trajectories = if enemy_depth > 0 {
      self
        .cur_trajectories
        .iter()
        .filter(|trajectory| trajectory.len() as u32 <= enemy_depth)
        .cloned()
        .collect()
    } else {
      Vec::new()
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories: self.rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  pub fn inc(
    &self,
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    should_stop: &AtomicBool,
  ) -> TrajectoriesPruning {
    let (mut cur_trajectories, mut enemy_trajectories) = if depth % 2 == 0 {
      let enemy_trajectories =
        TrajectoriesPruning::build_trajectories(field, player.next(), depth / 2, empty_board, should_stop);
      if should_stop.load(Ordering::Relaxed) {
        return TrajectoriesPruning::empty(self.rebuild_trajectories);
      }
      (self.cur_trajectories.clone(), enemy_trajectories)
    } else {
      let cur_trajectories =
        TrajectoriesPruning::build_trajectories(field, player, (depth + 1) / 2, empty_board, should_stop);
      if should_stop.load(Ordering::Relaxed) {
        return TrajectoriesPruning::empty(self.rebuild_trajectories);
      }
      (cur_trajectories, self.enemy_trajectories.clone())
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories: self.rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  pub fn moves(&self) -> &Vec<Pos> {
    &self.moves
  }

  pub fn moves_mut(&mut self) -> &mut Vec<Pos> {
    &mut self.moves
  }
}
<commit_msg>Add score to Trajectory.<commit_after>use oppai_field::field::{euclidean, wave_diag, Field, Pos};
use oppai_field::player::Player;
use std::{
  collections::HashSet,
  ops::Index,
  sync::atomic::{AtomicBool, Ordering},
};

#[derive(Debug, Clone)]
pub struct Trajectory {
  points: Vec<Pos>,
  hash: u64,
  score: i32,
}

impl Trajectory {
  pub fn new(points: Vec<Pos>, hash: u64, score: i32) -> Trajectory {
    Trajectory { points, hash, score }
  }

  pub fn points(&self) -> &Vec<Pos> {
    &self.points
  }

  pub fn hash(&self) -> u64 {
    self.hash
  }

  pub fn score(&self) -> i32 {
    self.score
  }

  pub fn len(&self) -> usize {
    self.points.len()
  }

  pub fn is_empty(&self) -> bool {
    self.points.is_empty()
  }
}

pub struct TrajectoriesPruning {
  rebuild_trajectories: bool,
  cur_trajectories: Vec<Trajectory>,
  enemy_trajectories: Vec<Trajectory>,
  moves: Vec<Pos>,
}

impl TrajectoriesPruning {
  fn add_trajectory(field: &Field, trajectories: &mut Vec<Trajectory>, points: &[Pos], player: Player) {
    for &pos in points {
      if !field.cell(pos).is_bound() || field.number_near_groups(pos, player) < 2 {
        return;
      }
    }
    let zobrist = field.zobrist();
    let mut hash = 0u64;
    for &pos in points {
      hash ^= zobrist.get_hash(pos);
    }
    for trajectory in trajectories.iter() {
      if trajectory.hash() == hash {
        return;
      }
    }
    let trajectory = Trajectory::new(points.to_vec(), hash, field.score(player));
    trajectories.push(trajectory);
  }

  fn next_moves(
    field: &Field,
    start_pos: Pos,
    player: Player,
    empty_board: &mut Vec<u32>,
    marks: &mut Vec<Pos>,
  ) -> Vec<Pos> {
    let mut moves = Vec::new();
    wave_diag(field.width(), start_pos, |pos| {
      if empty_board[pos] != 0 {
        return false;
      }
      let cell = field.cell(pos);
      if cell.is_players_point(player) {
        empty_board[pos] = 1;
        marks.push(pos);
        true
      } else {
        if cell.is_putting_allowed() && !cell.is_players_empty_base(player) {
          empty_board[pos] = 1;
          moves.push(pos);
        }
        false
      }
    });
    for &pos in &moves {
      empty_board[pos] = 0;
    }
    moves
  }

  fn build_trajectories_rec(
    field: &mut Field,
    trajectories: &mut Vec<Trajectory>,
    player: Player,
    cur_depth: u32,
    depth: u32,
    empty_board: &mut Vec<u32>,
    last_pos: Pos,
    moves: Vec<Pos>,
    should_stop: &AtomicBool,
  ) {
    for pos in moves {
      if should_stop.load(Ordering::Relaxed) {
        break;
      }
      if field.number_near_points(pos, player) >= 3 {
        continue;
      }
      let cell = field.cell(pos);
      if cell.is_players_empty_base(player.next()) {
        field.put_point(pos, player);
        if field.get_delta_score(player) > 0 {
          TrajectoriesPruning::add_trajectory(
            field,
            trajectories,
            field
              .points_seq()
              .index(field.moves_count() - cur_depth as usize..field.moves_count()),
            player,
          );
        }
        field.undo();
      } else {
        field.put_point(pos, player);
        if field.get_delta_score(player) > 0 {
          TrajectoriesPruning::add_trajectory(
            field,
            trajectories,
            field
              .points_seq()
              .index(field.moves_count() - cur_depth as usize..field.moves_count()),
            player,
          );
        } else if depth > 0 {
          let mut marks = Vec::new();
          let mut next_moves = TrajectoriesPruning::next_moves(field, pos, player, empty_board, &mut marks);
          if last_pos != 0 {
            next_moves.retain(|&next_pos| euclidean(field.width(), last_pos, next_pos) > 2);
          }
          TrajectoriesPruning::build_trajectories_rec(
            field,
            trajectories,
            player,
            cur_depth + 1,
            depth - 1,
            empty_board,
            pos,
            next_moves,
            should_stop,
          );
          for mark_pos in marks {
            empty_board[mark_pos] = 0;
          }
        }
        field.undo();
      }
    }
  }

  fn build_trajectories(
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    should_stop: &AtomicBool,
  ) -> Vec<Trajectory> {
    let mut trajectories = Vec::new();

    if depth == 0 {
      return trajectories;
    }

    let mut marks = Vec::new();
    for pos in field.points_seq().clone() {
      if field.cell(pos).get_player() != player {
        continue;
      }

      if should_stop.load(Ordering::Relaxed) {
        break;
      }

      let moves = TrajectoriesPruning::next_moves(field, pos, player, empty_board, &mut marks);

      TrajectoriesPruning::build_trajectories_rec(
        field,
        &mut trajectories,
        player,
        1,
        depth - 1,
        empty_board,
        0,
        moves,
        should_stop,
      );
    }

    for pos in marks {
      empty_board[pos] = 0;
    }

    trajectories
  }

  fn project(trajectories: &[Trajectory], empty_board: &mut Vec<u32>) {
    for &pos in trajectories.iter().flat_map(|trajectory| trajectory.points().iter()) {
      empty_board[pos] += 1;
    }
  }

  fn project_length(trajectories: &[Trajectory], empty_board: &mut Vec<u32>) {
    for trajectory in trajectories {
      let len = trajectory.len() as u32;
      for &pos in trajectory.points() {
        if empty_board[pos] == 0 || empty_board[pos] > len {
          empty_board[pos] = len;
        }
      }
    }
  }

  fn deproject(trajectories: &[Trajectory], empty_board: &mut Vec<u32>) {
    for &pos in trajectories.iter().flat_map(|trajectory| trajectory.points().iter()) {
      empty_board[pos] = 0;
    }
  }

  fn exclude_unnecessary_trajectories(trajectories: &mut Vec<Trajectory>, empty_board: &mut Vec<u32>) -> bool {
    let mut need_exclude = false;
    trajectories.retain(|trajectory| {
      let single_count = trajectory.points().iter().filter(|&&pos| empty_board[pos] == 1).count();
      if single_count > 1 {
        for &pos in trajectory.points() {
          empty_board[pos] -= 1;
        }
        need_exclude = true;
        false
      } else {
        true
      }
    });
    need_exclude
  }

  fn calculate_moves(
    trajectories1: &mut Vec<Trajectory>,
    trajectories2: &mut Vec<Trajectory>,
    empty_board: &mut Vec<u32>,
  ) -> Vec<Pos> {
    TrajectoriesPruning::project(trajectories1, empty_board);
    TrajectoriesPruning::project(trajectories2, empty_board);
    while TrajectoriesPruning::exclude_unnecessary_trajectories(trajectories1, empty_board)
      || TrajectoriesPruning::exclude_unnecessary_trajectories(trajectories2, empty_board)
    {}
    let mut result_set = HashSet::new();
    for &pos in trajectories1
      .iter()
      .chain(trajectories2.iter())
      .flat_map(|trajectory| trajectory.points().iter())
    {
      result_set.insert(pos);
    }
    let mut result = result_set.into_iter().collect::<Vec<Pos>>();
    result.sort_unstable_by(|&pos1, &pos2| empty_board[pos2].cmp(&empty_board[pos1]));
    TrajectoriesPruning::deproject(trajectories1, empty_board);
    TrajectoriesPruning::deproject(trajectories2, empty_board);
    TrajectoriesPruning::project_length(trajectories1, empty_board);
    TrajectoriesPruning::project_length(trajectories2, empty_board);
    result.sort_by(|&pos1, &pos2| empty_board[pos1].cmp(&empty_board[pos2]));
    TrajectoriesPruning::deproject(trajectories1, empty_board);
    TrajectoriesPruning::deproject(trajectories2, empty_board);
    result
  }

  #[inline]
  pub fn empty(rebuild_trajectories: bool) -> TrajectoriesPruning {
    TrajectoriesPruning {
      rebuild_trajectories,
      cur_trajectories: Vec::with_capacity(0),
      enemy_trajectories: Vec::with_capacity(0),
      moves: Vec::with_capacity(0),
    }
  }

  pub fn new(
    rebuild_trajectories: bool,
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    should_stop: &AtomicBool,
  ) -> TrajectoriesPruning {
    if depth == 0 {
      return TrajectoriesPruning::empty(rebuild_trajectories);
    }
    let mut cur_trajectories =
      TrajectoriesPruning::build_trajectories(field, player, (depth + 1) / 2, empty_board, should_stop);
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(rebuild_trajectories);
    }
    let mut enemy_trajectories =
      TrajectoriesPruning::build_trajectories(field, player.next(), depth / 2, empty_board, should_stop);
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  fn last_pos_trajectory(field: &Field, player: Player, depth: u32, last_pos: Pos) -> Option<Trajectory> {
    let mut points = Vec::with_capacity(4);
    let mut hash = 0;
    for &pos in &field.directions(last_pos) {
      if field.cell(pos).is_putting_allowed() {
        let mut neighbors_count = 0;
        for &neighbor in &field.directions(pos) {
          if field.cell(neighbor).is_players_point(player) {
            neighbors_count += 1;
          }
        }
        if neighbors_count < 3 {
          points.push(pos);
          hash ^= field.zobrist().get_hash(pos);
        }
      } else if !field.cell(pos).is_players_point(player) {
        return None;
      }
    }
    if points.len() as u32 <= (depth + 1) / 2 {
      Some(Trajectory::new(points, hash, field.score(player) + 1))
    } else {
      None
    }
  }

  pub fn next(
    &self,
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    last_pos: Pos,
    should_stop: &AtomicBool,
  ) -> TrajectoriesPruning {
    if depth == 0 {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let mut cur_trajectories = if self.rebuild_trajectories {
      TrajectoriesPruning::build_trajectories(field, player, (depth + 1) / 2, empty_board, should_stop)
    } else {
      self
        .enemy_trajectories
        .iter()
        .filter(|trajectory| {
          trajectory
            .points()
            .iter()
            .all(|&pos| field.cell(pos).is_putting_allowed())
        })
        .cloned()
        .chain(TrajectoriesPruning::last_pos_trajectory(field, player, depth, last_pos).into_iter())
        .collect()
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let enemy_depth = depth / 2;
    let mut enemy_trajectories = if enemy_depth > 0 {
      self
        .cur_trajectories
        .iter()
        .filter_map(|trajectory| {
          let len = trajectory.len() as u32;
          let contains_pos = trajectory.points().contains(&last_pos);
          if (len <= enemy_depth || len == enemy_depth + 1 && contains_pos)
            && trajectory
              .points()
              .iter()
              .all(|&pos| field.cell(pos).is_putting_allowed() || pos == last_pos)
          {
            let new_trajectory = if contains_pos {
              if len == 1 {
                return None;
              }
              Trajectory::new(
                trajectory
                  .points
                  .iter()
                  .cloned()
                  .filter(|&pos| pos != last_pos)
                  .collect(),
                trajectory.hash() ^ field.zobrist().get_hash(last_pos),
                trajectory.score,
              )
            } else {
              trajectory.clone()
            };
            Some(new_trajectory)
          } else {
            None
          }
        })
        .collect()
    } else {
      Vec::new()
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories: self.rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  pub fn dec_and_swap(&self, depth: u32, empty_board: &mut Vec<u32>, should_stop: &AtomicBool) -> TrajectoriesPruning {
    if depth == 0 {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let mut cur_trajectories = self.enemy_trajectories.clone();
    let enemy_depth = depth / 2;
    let mut enemy_trajectories = if enemy_depth > 0 {
      self
        .cur_trajectories
        .iter()
        .filter(|trajectory| trajectory.len() as u32 <= enemy_depth)
        .cloned()
        .collect()
    } else {
      Vec::new()
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories: self.rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  pub fn inc(
    &self,
    field: &mut Field,
    player: Player,
    depth: u32,
    empty_board: &mut Vec<u32>,
    should_stop: &AtomicBool,
  ) -> TrajectoriesPruning {
    let (mut cur_trajectories, mut enemy_trajectories) = if depth % 2 == 0 {
      let enemy_trajectories =
        TrajectoriesPruning::build_trajectories(field, player.next(), depth / 2, empty_board, should_stop);
      if should_stop.load(Ordering::Relaxed) {
        return TrajectoriesPruning::empty(self.rebuild_trajectories);
      }
      (self.cur_trajectories.clone(), enemy_trajectories)
    } else {
      let cur_trajectories =
        TrajectoriesPruning::build_trajectories(field, player, (depth + 1) / 2, empty_board, should_stop);
      if should_stop.load(Ordering::Relaxed) {
        return TrajectoriesPruning::empty(self.rebuild_trajectories);
      }
      (cur_trajectories, self.enemy_trajectories.clone())
    };
    if should_stop.load(Ordering::Relaxed) {
      return TrajectoriesPruning::empty(self.rebuild_trajectories);
    }
    let moves = TrajectoriesPruning::calculate_moves(&mut cur_trajectories, &mut enemy_trajectories, empty_board);
    TrajectoriesPruning {
      rebuild_trajectories: self.rebuild_trajectories,
      cur_trajectories,
      enemy_trajectories,
      moves,
    }
  }

  pub fn moves(&self) -> &Vec<Pos> {
    &self.moves
  }

  pub fn moves_mut(&mut self) -> &mut Vec<Pos> {
    &mut self.moves
  }
}
<|endoftext|>


<commit_before>/// Just a few dummy functions if smoltcp support is disabled

// A handle, identifying a socket
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
pub struct Handle(usize);

#[no_mangle]
pub fn sys_socket_connect(_ip: &[u8], _port: u16, _timeout: Option<u64>) -> Result<Handle, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_socket_read(_handle: Handle, _buffer: &mut [u8]) -> Result<usize, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_socket_write(_handle: Handle, _buffer: &[u8]) -> Result<usize, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_socket_close(_handle: Handle) -> Result<(), ()> {
	Err(())
}
<commit_msg>add missing dummy functions if smoltcp isn't enabled<commit_after>/// Just a few dummy functions if smoltcp support is disabled

// A handle, identifying a socket
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
pub struct Handle(usize);

#[no_mangle]
pub fn sys_tcp_stream_connect(_ip: &[u8], _port: u16, _timeout: Option<u64>) -> Result<Handle, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_read(_handle: Handle, _buffer: &mut [u8]) -> Result<usize, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_write(_handle: Handle, _buffer: &[u8]) -> Result<usize, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_close(_handle: Handle) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_read_timeout(_handle: Handle, _timeout: Option<u64>) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_read_timeout(_handle: Handle) -> Result<Option<u64>, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_write_timeout(_handle: Handle, _timeout: Option<u64>) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_write_timeout(_handle: Handle) -> Result<Option<u64>, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_duplicate(_handle: Handle) -> Result<Handle, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_peek(_handle: Handle, _buf: &mut [u8]) -> Result<usize, ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_nonblocking(_handle: Handle, _mode: bool) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_set_tll(_handle: Handle, _ttl: u32) -> Result<(), ()> {
	Err(())
}

#[no_mangle]
pub fn sys_tcp_stream_get_tll(_handle: Handle) -> Result<u32, ()> {
	Err(())
}
<|endoftext|>


<commit_before>//! Types for the *m.call.candidates* event.

use js_int::UInt;
use ruma_events_macros::ruma_event;
use serde::{Deserialize, Serialize};

ruma_event! {
    /// This event is sent by callers after sending an invite and by the callee after answering.
    /// Its purpose is to give the other party additional ICE candidates to try using to
    /// communicate.
    CandidatesEvent {
        kind: RoomEvent,
        event_type: "m.call.candidates",
        content: {
            /// The ID of the call this event relates to.
            pub call_id: String,

            /// A list of candidates.
            pub candidates: Vec<Candidate>,

            /// The version of the VoIP specification this messages adheres to.
            pub version: UInt,
        },
    }
}

/// An ICE (Interactive Connectivity Establishment) candidate.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct Candidate {
    /// The SDP "a" line of the candidate.
    pub candidate: String,

    /// The SDP media type this candidate is intended for.
    #[serde(rename = "sdpMid")]
    pub sdp_mid: String,

    /// The index of the SDP "m" line this candidate is intended for.
    #[serde(rename = "sdpMLineIndex")]
    pub sdp_m_line_index: UInt,
}
<commit_msg>Update serde attrs in call::candidates<commit_after>//! Types for the *m.call.candidates* event.

use js_int::UInt;
use ruma_events_macros::ruma_event;
use serde::{Deserialize, Serialize};

ruma_event! {
    /// This event is sent by callers after sending an invite and by the callee after answering.
    /// Its purpose is to give the other party additional ICE candidates to try using to
    /// communicate.
    CandidatesEvent {
        kind: RoomEvent,
        event_type: "m.call.candidates",
        content: {
            /// The ID of the call this event relates to.
            pub call_id: String,

            /// A list of candidates.
            pub candidates: Vec<Candidate>,

            /// The version of the VoIP specification this messages adheres to.
            pub version: UInt,
        },
    }
}

/// An ICE (Interactive Connectivity Establishment) candidate.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Candidate {
    /// The SDP "a" line of the candidate.
    pub candidate: String,

    /// The SDP media type this candidate is intended for.
    pub sdp_mid: String,

    /// The index of the SDP "m" line this candidate is intended for.
    pub sdp_m_line_index: UInt,
}
<|endoftext|>


<commit_before>use std::collections::{BTreeSet,BTreeMap};
use std::collections::btree_map;
use std::iter::FromIterator;

fn build_stopwords() -> BTreeSet<&'static str> {
    BTreeSet::from_iter(vec!["with", "sign", "small", "letter", "digit", "for", "symbol", "<control>"].iter().map(|s| *s))
}

#[test]
fn test_stopwords() {
    let sw = build_stopwords();
    assert!(sw.contains("with"));
}

fn name_components(name: &str) -> Vec<String> {
    lazy_static! {
        static ref STOPS: BTreeSet<&'static str> = build_stopwords();
    }
    let mut result = vec!();
    result.push(name.to_lowercase().to_owned());
    for component in name.split_whitespace() {
        let component = component.to_lowercase();
        let component = component.trim_right_matches(',');

        if STOPS.contains(component) || component.len() == 1 {
            continue;
        }
        result.push(component.to_owned());
    }
    result
}

#[test]
fn test_name_components() {
    assert_eq!(name_components("D WITH CURL, LATIN SMALL LETTER"),
               Vec::from_iter(vec!["d with curl, latin small letter", "curl", "latin"]
                              .iter().map(|s| String::from(*s))));
    assert_eq!(name_components("Equals Sign"),
               Vec::from_iter(vec!["equals sign", "equals"]
                              .iter().map(|s| String::from(*s))));

}

#[derive(Clone, Debug, PartialEq)]
pub struct Names {
    map: BTreeMap<String, BTreeSet<char>>,
}

impl Names {
    pub fn new() -> Names {
        Names{map: BTreeMap::new()}
    }

    ///Insert a character names' components into btree map, minus stopwords.
    pub fn insert<'a>(&mut self, names: Vec<String>, ch: char) {
        for name in names {
            for component in name_components(name.as_str()) {
                self.map.entry(component).or_insert_with(BTreeSet::new).insert(ch);
            }
        }
    }

    pub fn iter(&self) -> btree_map::Iter<String, BTreeSet<char>> {
        self.map.iter()
    }
}
<commit_msg>Clean up the code a little with into_iter<commit_after>use std::collections::{BTreeSet,BTreeMap};
use std::collections::btree_map;
use std::iter::FromIterator;

fn build_stopwords() -> BTreeSet<&'static str> {
    BTreeSet::from_iter(vec!["with", "sign", "small", "letter", "digit", "for", "symbol", "<control>"].into_iter())
}

#[test]
fn test_stopwords() {
    let sw = build_stopwords();
    assert!(sw.contains("with"));
}

fn name_components(name: &str) -> Vec<String> {
    lazy_static! {
        static ref STOPS: BTreeSet<&'static str> = build_stopwords();
    }
    let mut result = vec!();
    result.push(name.to_lowercase().to_owned());
    for component in name.split_whitespace() {
        let component = component.to_lowercase();
        let component = component.trim_right_matches(',');

        if STOPS.contains(component) || component.len() == 1 {
            continue;
        }
        result.push(component.to_owned());
    }
    result
}

#[test]
fn test_name_components() {
    assert_eq!(name_components("D WITH CURL, LATIN SMALL LETTER"),
               Vec::from_iter(vec!["d with curl, latin small letter", "curl", "latin"]
                              .into_iter().map(|s| String::from(s))));
    assert_eq!(name_components("Equals Sign"),
               Vec::from_iter(vec!["equals sign", "equals"]
                              .into_iter().map(|s| String::from(s))));

}

#[derive(Clone, Debug, PartialEq)]
pub struct Names {
    map: BTreeMap<String, BTreeSet<char>>,
}

impl Names {
    pub fn new() -> Names {
        Names{map: BTreeMap::new()}
    }

    ///Insert a character names' components into btree map, minus stopwords.
    pub fn insert<'a>(&mut self, names: Vec<String>, ch: char) {
        for name in names {
            for component in name_components(name.as_str()) {
                self.map.entry(component).or_insert_with(BTreeSet::new).insert(ch);
            }
        }
    }

    pub fn iter(&self) -> btree_map::Iter<String, BTreeSet<char>> {
        self.map.iter()
    }
}
<|endoftext|>


<commit_before>use game::constants::PISTOL_AUDIO_PATH;
use rodio;
use rodio::Sink;
use std::fs::File;
use std::io::BufReader;

pub struct CharacterAudio {
  sink: Sink,
}

impl CharacterAudio {
  pub fn new() -> CharacterAudio {
    #[allow(deprecated)]
    let endpoint = rodio::get_default_endpoint().unwrap();
    CharacterAudio {
      sink: Sink::new(&endpoint),
    }
  }

  pub fn play_pistol(&self) {
    if self.sink.empty() {
      let file = File::open(PISTOL_AUDIO_PATH).unwrap();
      let pistol_data = rodio::Decoder::new(BufReader::new(file)).unwrap();
      self.sink.append(pistol_data);
    }
  }
}
<commit_msg>Use "default_endpoint" instead of deprecated "get_default_endpoint"<commit_after>use game::constants::PISTOL_AUDIO_PATH;
use rodio;
use rodio::Sink;
use std::fs::File;
use std::io::BufReader;

pub struct CharacterAudio {
  sink: Sink,
}

impl CharacterAudio {
  pub fn new() -> CharacterAudio {
    let endpoint = rodio::default_endpoint().unwrap();
    CharacterAudio {
      sink: Sink::new(&endpoint),
    }
  }

  pub fn play_pistol(&self) {
    if self.sink.empty() {
      let file = File::open(PISTOL_AUDIO_PATH).unwrap();
      let pistol_data = rodio::Decoder::new(BufReader::new(file)).unwrap();
      self.sink.append(pistol_data);
    }
  }
}
<|endoftext|>


<commit_before>
use std::iter;
use std::io::{Write};
use std::io;

use encoding::types::{EncodingRef, EncoderTrap};
use encoding::all::{UTF_8};
use byteorder::{LittleEndian, WriteBytesExt};

use consts;
use img::{Image};

pub struct Printer<W: io::Write> {
    writer: io::BufWriter<W>,
    codec: EncodingRef,
    trap: EncoderTrap
}

impl<W: io::Write> Printer<W> {
    pub fn new(writer: W,
               codec: Option<EncodingRef>,
               trap: Option<EncoderTrap>) -> Printer<W> {
        Printer{
            writer: io::BufWriter::new(writer),
            codec: codec.unwrap_or(UTF_8 as EncodingRef),
            trap: trap.unwrap_or(EncoderTrap::Replace)
        }
    }

    fn encode(&mut self, content: &str) -> Vec<u8> {
        self.codec.encode(content, self.trap).unwrap()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.writer.write(buf)
    }

    pub fn write_u8(&mut self, n: u8) -> io::Result<usize> {
        self.write(vec!(n).as_slice())
    }

    fn write_u16le(&mut self, n: u16) -> io::Result<usize> {
        let mut wtr = vec![];
        wtr.write_u16::<LittleEndian>(n).unwrap();
        self.write(wtr.as_slice())
    }

    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }

    pub fn hwinit(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_INIT);
        self
    }

    pub fn hwselect(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_SELECT);
        self
    }

    pub fn hwreset(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_RESET);
        self
    }

    pub fn print(&mut self, content: &str) -> &mut Printer<W> {
        // let rv = self.encode(content);
        let rv = self.encode(content);
        let _ = self.write(rv.as_slice());
        self
    }

    pub fn println(&mut self, content: &str) -> &mut Printer<W> {
        self.print(format!("{}{}", content, consts::EOL).as_ref());
        self
    }

    pub fn text(&mut self, content: &str) -> &mut Printer<W> {
        self.println(content);
        self
    }

    pub fn line_space(&mut self, n: i32) -> &mut Printer<W> {
        if n >= 0 {
            let _ = self.write(consts::LS_SET);
            let _ = self.write_u8(n as u8);
        } else {
            let _ = self.write(consts::LS_DEFAULT);
        }
        self
    }

    pub fn feed(&mut self, n: usize) -> &mut Printer<W> {
        let n = if n < 1 { 1 } else { n };
        let _ = self.write(iter::repeat(consts::EOL)
                           .take(n)
                           .collect::<String>()
                           .as_ref());
        self
    }

    pub fn control(&mut self, ctrl: &str) -> &mut Printer<W> {
        let ctrl_upper = ctrl.to_uppercase();
        let ctrl_value = match ctrl_upper.as_ref() {
            "LF" => consts::CTL_LF,
            "FF" => consts::CTL_FF,
            "CR" => consts::CTL_CR,
            "HT" => consts::CTL_HT,
            "VT" => consts::CTL_VT,
            _ => panic!("Invalid control action: {}", ctrl)
        };
        let _ = self.write(ctrl_value);
        self
    }

    pub fn align(&mut self, alignment: &str) -> &mut Printer<W> {
        let align_upper = alignment.to_uppercase();
        let align_value = match align_upper.as_ref() {
            "LT" => consts::TXT_ALIGN_LT,
            "CT" => consts::TXT_ALIGN_CT,
            "RT" => consts::TXT_ALIGN_RT,
            _ => panic!("Invalid alignment: {}", alignment)
        };
        let _ = self.write(align_value);
        self
    }

    pub fn font(&mut self, family: &str) -> &mut Printer<W> {
        let family_upper = family.to_uppercase();
        let family_value = match family_upper.as_ref() {
            "A" => consts::TXT_FONT_A,
            "B" => consts::TXT_FONT_B,
            "C" => consts::TXT_FONT_C,
            _ => panic!("Invalid font family: {}", family)
        };
        let _ = self.write(family_value);
        self
    }

    pub fn style(&mut self, kind: &str) -> &mut Printer<W> {
        let kind_upper = kind.to_uppercase();
        match kind_upper.as_ref() {
            "B" => {
                let _ = self.write(consts::TXT_UNDERL_OFF);
                let _ = self.write(consts::TXT_BOLD_ON);
            }
            "U" => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL_ON);
            }
            "U2" => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL2_ON);
            }
            "BU" => {
                let _ = self.write(consts::TXT_BOLD_ON);
                let _ = self.write(consts::TXT_UNDERL_ON);
            }
            "BU2" => {
                let _ = self.write(consts::TXT_BOLD_ON);
                let _ = self.write(consts::TXT_UNDERL2_ON);
            }
            "NORMAL" | _ => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL_OFF);
            }
        }
        self
    }

    pub fn size(&mut self, width: usize, height: usize) -> &mut Printer<W> {
        let _ = self.write(consts::TXT_NORMAL);
        if width == 2 {
            let _ = self.write(consts::TXT_2WIDTH);
        }
        if height == 2 {
            let _ = self.write(consts::TXT_2HEIGHT);
        }
        self
    }

    pub fn hardware(&mut self, hw: &str) -> &mut Printer<W> {
        let value = match hw {
            "INIT" => consts::HW_INIT,
            "SELECT" => consts::HW_SELECT,
            "RESET" => consts::HW_RESET,
            _ => panic!("Invalid hardware command: {}", hw)
        };
        let _ = self.write(value);
        self
    }

    pub fn barcode(&mut self,
                   code: &str,
                   kind: &str,
                   position: &str,
                   font: &str,
                   width: usize, height: usize) -> &mut Printer<W> {
        if width >= 1 || width <= 255 {
            let _ = self.write(consts::BARCODE_WIDTH);
        }
        if height >= 2 || height <= 6 {
            let _ = self.write(consts::BARCODE_HEIGHT);
        }

        let font = font.to_uppercase();
        let position = position.to_uppercase();
        let kind = kind.to_uppercase().replace("-", "_");
        let font_value = match font.as_ref() {
            "B" => consts::BARCODE_FONT_B,
            "A" | _ => consts::BARCODE_FONT_A
        };
        let txt_value = match position.as_ref() {
            "OFF" => consts::BARCODE_TXT_OFF,
            "ABV" => consts::BARCODE_TXT_ABV,
            "BTH" => consts::BARCODE_TXT_BTH,
            "BLW" | _ => consts::BARCODE_TXT_BLW,
        };
        let kind_value = match kind.as_ref() {
            "UPC_A"  => consts::BARCODE_UPC_A,
            "UPC_E"  => consts::BARCODE_UPC_E,
            "EAN8"   => consts::BARCODE_EAN8,
            "CODE39" => consts::BARCODE_CODE39,
            "ITF"    => consts::BARCODE_ITF,
            "NW7"    => consts::BARCODE_NW7,
            "EAN13" | _ => consts::BARCODE_EAN13
        };
        let _ = self.write(font_value);
        let _ = self.write(txt_value);
        let _ = self.write(kind_value);
        let _ = self.write(code.as_bytes());
        self
    }

    #[cfg(feature="qrcode")]
    pub fn qrimage(&mut self) -> &mut Printer<W> {
        self
    }

    #[cfg(feature="qrcode")]
    pub fn qrcode(&mut self,
                  code: &str,
                  version: Option<i32>,
                  level: &str,
                  size: Option<i32>) -> &mut Printer<W> {
        let level = level.to_uppercase();
        let level_value = match level.as_ref() {
            "M" => consts::QR_LEVEL_M,
            "Q" => consts::QR_LEVEL_Q,
            "H" => consts::QR_LEVEL_H,
            "L" | _ => consts::QR_LEVEL_L,
        };
        let _ = self.write(consts::TYPE_QR);
        let _ = self.write(consts::CODE2D);
        let _ = self.write_u8(version.unwrap_or(3) as u8);
        let _ = self.write(level_value);
        let _ = self.write_u8(size.unwrap_or(3) as u8);
        let _ = self.write_u16le(code.len() as u16);
        let _ = self.write(code.as_bytes());
        self
    }

    pub fn cashdraw(&mut self, pin: i32) -> &mut Printer<W> {
        let pin_value = if pin == 5 {
            consts::CD_KICK_5
        } else {
            consts::CD_KICK_2
        };
        let _ = self.write(pin_value);
        self
    }

    pub fn cut(&mut self, part: bool) -> &mut Printer<W> {
        self.print(iter::repeat(consts::EOL)
                   .take(3)
                   .collect::<String>()
                   .as_ref());
        let paper_cut_type = if part {
            consts::PAPER_PART_CUT
        } else {
            consts::PAPER_FULL_CUT
        };
        let _ = self.write(paper_cut_type);
        self
    }

    pub fn bit_image(&mut self,
                    image: &Image,
                    density: Option<&str>) -> &mut Printer<W> {
        let density = density.unwrap_or("d24");
        let density_upper = density.to_uppercase();
        let header = match density_upper.as_ref() {
            "S8"  => consts::BITMAP_S8,
            "D8"  => consts::BITMAP_D8,
            "S24" => consts::BITMAP_S24,
            "D24" | _ => consts::BITMAP_D24,
        };
        let n = if density == "s8" || density == "d8" { 1 } else { 3 };
        self.line_space(0);
        for line in image.bitimage_lines(n*8) {
            let _ = self.write(header);
            let _ = self.write_u16le((line.len() / n as usize) as u16);
            let _ = self.write(line.as_ref());
            self.feed(1);
        }
        self
    }

    pub fn raster(&mut self, image: &Image, mode: Option<&str>) -> &mut Printer<W> {
        let mode_upper = mode.unwrap_or("NORMAL").to_uppercase();
        let header = match mode_upper.as_ref() {
            "DH" => consts::GSV0_DH,
            "DWDH" => consts::GSV0_DWDH,
            "DW" => consts::GSV0_DW,
            "NORMAL" | _ => consts::GSV0_NORMAL,
        };
        let _ = self.write(header);
        let _ = self.write_u16le(((image.width+7)/8) as u16);
        let _ = self.write_u16le(image.height as u16);
        let _ = self.write(image.get_raster().as_ref());
        self
    }
}
<commit_msg>Changed printer.rs to report IO status for each write call<commit_after>use std::io;
use std::io::Write;
use std::iter;

use byteorder::{LittleEndian, WriteBytesExt};
use encoding::all::UTF_8;
use encoding::types::{EncoderTrap, EncodingRef};

use consts;
use img::Image;

pub struct Printer<W: io::Write> {
    writer: io::BufWriter<W>,
    codec: EncodingRef,
    trap: EncoderTrap,
}

impl<W: io::Write> Printer<W> {
    pub fn new(writer: W, codec: Option<EncodingRef>, trap: Option<EncoderTrap>) -> Printer<W> {
        Printer {
            writer: io::BufWriter::new(writer),
            codec: codec.unwrap_or(UTF_8 as EncodingRef),
            trap: trap.unwrap_or(EncoderTrap::Replace),
        }
    }

    fn encode(&mut self, content: &str) -> Vec<u8> {
        self.codec.encode(content, self.trap).unwrap()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.writer.write(buf)
    }

    pub fn write_u8(&mut self, n: u8) -> io::Result<usize> {
        self.write(vec![n].as_slice())
    }

    fn write_u16le(&mut self, n: u16) -> io::Result<usize> {
        let mut wtr = vec![];
        wtr.write_u16::<LittleEndian>(n).unwrap();
        self.write(wtr.as_slice())
    }

    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }

    pub fn hwinit(&mut self) -> io::Result<usize> {
        self.write(consts::HW_INIT)
    }

    pub fn hwselect(&mut self) -> io::Result<usize> {
        self.write(consts::HW_SELECT)
    }

    pub fn hwreset(&mut self) -> io::Result<usize> {
        self.write(consts::HW_RESET)
    }

    pub fn print(&mut self, content: &str) -> io::Result<usize> {
        // let rv = self.encode(content);
        let rv = self.encode(content);
        self.write(rv.as_slice())
    }

    pub fn println(&mut self, content: &str) -> io::Result<usize> {
        self.print(format!("{}{}", content, consts::EOL).as_ref())
    }

    pub fn text(&mut self, content: &str) -> io::Result<usize> {
        self.println(content)
    }

    pub fn line_space(&mut self, n: i32) -> io::Result<usize> {
        if n >= 0 {
            Ok(self.write(consts::LS_SET)? + self.write_u8(n as u8)?)
        } else {
            self.write(consts::LS_DEFAULT)
        }
    }

    pub fn feed(&mut self, n: usize) -> io::Result<usize> {
        let n = if n < 1 { 1 } else { n };
        self.write(
            iter::repeat(consts::EOL)
                .take(n)
                .collect::<String>()
                .as_ref(),
        )
    }

    pub fn control(&mut self, ctrl: &str) -> io::Result<usize> {
        let ctrl_upper = ctrl.to_uppercase();
        let ctrl_value = match ctrl_upper.as_ref() {
            "LF" => consts::CTL_LF,
            "FF" => consts::CTL_FF,
            "CR" => consts::CTL_CR,
            "HT" => consts::CTL_HT,
            "VT" => consts::CTL_VT,
            _ => panic!("Invalid control action: {}", ctrl),
        };
        self.write(ctrl_value)
    }

    pub fn align(&mut self, alignment: &str) -> io::Result<usize> {
        let align_upper = alignment.to_uppercase();
        let align_value = match align_upper.as_ref() {
            "LT" => consts::TXT_ALIGN_LT,
            "CT" => consts::TXT_ALIGN_CT,
            "RT" => consts::TXT_ALIGN_RT,
            _ => panic!("Invalid alignment: {}", alignment),
        };
        self.write(align_value)
    }

    pub fn font(&mut self, family: &str) -> io::Result<usize> {
        let family_upper = family.to_uppercase();
        let family_value = match family_upper.as_ref() {
            "A" => consts::TXT_FONT_A,
            "B" => consts::TXT_FONT_B,
            "C" => consts::TXT_FONT_C,
            _ => panic!("Invalid font family: {}", family),
        };
        self.write(family_value)
    }

    pub fn style(&mut self, kind: &str) -> io::Result<usize> {
        let kind_upper = kind.to_uppercase();
        match kind_upper.as_ref() {
            "B" => Ok(self.write(consts::TXT_UNDERL_OFF)? + self.write(consts::TXT_BOLD_ON)?),
            "U" => Ok(self.write(consts::TXT_BOLD_OFF)? + self.write(consts::TXT_UNDERL_ON)?),
            "U2" => Ok(self.write(consts::TXT_BOLD_OFF)? + self.write(consts::TXT_UNDERL2_ON)?),
            "BU" => Ok(self.write(consts::TXT_BOLD_ON)? + self.write(consts::TXT_UNDERL_ON)?),
            "BU2" => Ok(self.write(consts::TXT_BOLD_ON)? + self.write(consts::TXT_UNDERL2_ON)?),
            "NORMAL" | _ => {
                Ok(self.write(consts::TXT_BOLD_OFF)? + self.write(consts::TXT_UNDERL_OFF)?)
            }
        }
    }

    pub fn size(&mut self, width: usize, height: usize) -> io::Result<usize> {
        let mut n = self.write(consts::TXT_NORMAL)?;
        if width == 2 {
            n += self.write(consts::TXT_2WIDTH)?;
        }
        if height == 2 {
            n += self.write(consts::TXT_2HEIGHT)?;
        }
        Ok(n)
    }

    pub fn hardware(&mut self, hw: &str) -> io::Result<usize> {
        let value = match hw {
            "INIT" => consts::HW_INIT,
            "SELECT" => consts::HW_SELECT,
            "RESET" => consts::HW_RESET,
            _ => panic!("Invalid hardware command: {}", hw),
        };
        self.write(value)
    }

    pub fn barcode(
        &mut self,
        code: &str,
        kind: &str,
        position: &str,
        font: &str,
        width: usize,
        height: usize,
    ) -> io::Result<usize> {
        let mut n = 0;
        if width >= 1 || width <= 255 {
            n += self.write(consts::BARCODE_WIDTH)?;
        }
        if height >= 2 || height <= 6 {
            n += self.write(consts::BARCODE_HEIGHT)?;
        }

        let font = font.to_uppercase();
        let position = position.to_uppercase();
        let kind = kind.to_uppercase().replace("-", "_");
        let font_value = match font.as_ref() {
            "B" => consts::BARCODE_FONT_B,
            "A" | _ => consts::BARCODE_FONT_A,
        };
        let txt_value = match position.as_ref() {
            "OFF" => consts::BARCODE_TXT_OFF,
            "ABV" => consts::BARCODE_TXT_ABV,
            "BTH" => consts::BARCODE_TXT_BTH,
            "BLW" | _ => consts::BARCODE_TXT_BLW,
        };
        let kind_value = match kind.as_ref() {
            "UPC_A" => consts::BARCODE_UPC_A,
            "UPC_E" => consts::BARCODE_UPC_E,
            "EAN8" => consts::BARCODE_EAN8,
            "CODE39" => consts::BARCODE_CODE39,
            "ITF" => consts::BARCODE_ITF,
            "NW7" => consts::BARCODE_NW7,
            "EAN13" | _ => consts::BARCODE_EAN13,
        };
        n += self.write(font_value)?;
        self.write(txt_value)?;
        self.write(kind_value)?;
        self.write(code.as_bytes())?;
        Ok(n)
    }

    #[cfg(feature = "qrcode")]
    pub fn qrimage(&mut self) -> io::Result<usize> {}

    #[cfg(feature = "qrcode")]
    pub fn qrcode(
        &mut self,
        code: &str,
        version: Option<i32>,
        level: &str,
        size: Option<i32>,
    ) -> io::Result<usize> {
        let level = level.to_uppercase();
        let level_value = match level.as_ref() {
            "M" => consts::QR_LEVEL_M,
            "Q" => consts::QR_LEVEL_Q,
            "H" => consts::QR_LEVEL_H,
            "L" | _ => consts::QR_LEVEL_L,
        };
        let mut n = 0;
        n += self.write(consts::TYPE_QR)?;
        n += self.write(consts::CODE2D)?;
        n += self.write_u8(version.unwrap_or(3) as u8)?;
        n += self.write(level_value)?;
        n += self.write_u8(size.unwrap_or(3) as u8)?;
        n += self.write_u16le(code.len() as u16)?;
        n += self.write(code.as_bytes())?;
        Ok(n)
    }

    pub fn cashdraw(&mut self, pin: i32) -> io::Result<usize> {
        let pin_value = if pin == 5 {
            consts::CD_KICK_5
        } else {
            consts::CD_KICK_2
        };
        self.write(pin_value)
    }

    pub fn cut(&mut self, part: bool) -> io::Result<usize> {
        let mut n_bytes = 0;
        n_bytes += self.print(
            iter::repeat(consts::EOL)
                .take(3)
                .collect::<String>()
                .as_ref(),
        )?;
        let paper_cut_type = if part {
            consts::PAPER_PART_CUT
        } else {
            consts::PAPER_FULL_CUT
        };
        n_bytes += self.write(paper_cut_type)?;
        Ok(n_bytes)
    }

    pub fn bit_image(&mut self, image: &Image, density: Option<&str>) -> io::Result<usize> {
        let density = density.unwrap_or("d24");
        let density_upper = density.to_uppercase();
        let header = match density_upper.as_ref() {
            "S8" => consts::BITMAP_S8,
            "D8" => consts::BITMAP_D8,
            "S24" => consts::BITMAP_S24,
            "D24" | _ => consts::BITMAP_D24,
        };
        let n = if density == "s8" || density == "d8" {
            1
        } else {
            3
        };
        let mut n_bytes = 0;
        n_bytes += self.line_space(0)?;
        for line in image.bitimage_lines(n * 8) {
            n_bytes += self.write(header)?;
            n_bytes += self.write_u16le((line.len() / n as usize) as u16)?;
            n_bytes += self.write(line.as_ref())?;
            n_bytes += self.feed(1)?;
        }
        Ok(n_bytes)
    }

    pub fn raster(&mut self, image: &Image, mode: Option<&str>) -> io::Result<usize> {
        let mode_upper = mode.unwrap_or("NORMAL").to_uppercase();
        let header = match mode_upper.as_ref() {
            "DH" => consts::GSV0_DH,
            "DWDH" => consts::GSV0_DWDH,
            "DW" => consts::GSV0_DW,
            "NORMAL" | _ => consts::GSV0_NORMAL,
        };
        let mut n_bytes = 0;
        n_bytes += self.write(header)?;
        n_bytes += self.write_u16le(((image.width+7)/8) as u16)?;
        n_bytes += self.write_u16le(image.height as u16)?;
        n_bytes += self.write(image.get_raster().as_ref())?;
        Ok(n_bytes)
    }
}
<|endoftext|>