<commit_before>use super::{Syllable,SyllableOptions,Subtitles,SubtitlesOptions,AsSyllableOptions};
use super::pos::{RowPosition,Size};
use std::ops::Deref;

#[derive(Debug,Serialize,Deserialize,Clone)]
pub struct Sentence {
    pub syllables: Vec<Syllable>,
    #[serde(skip_serializing,skip_deserializing)]
    pub position: RowPosition,
    #[serde(skip_serializing_if="Option::is_none")]
    pub sentence_options: Option<SentenceOptions>,
}

pub trait AsSentenceOptions {
    fn as_sentence_options(&self) -> Option<&SentenceOptions>;
    fn or_sentence_options(&self,other:Option<&SentenceOptions>) -> Option<SentenceOptions> {
        match (self.as_sentence_options(),other) {
            (Some(s),Some(other)) => Some(SentenceOptions {
                transitions: {
                    use std::cmp::Ord;
                    let mut t = s.transitions.iter()
                        .chain(other.transitions.iter())
                        .cloned()
                        .collect::<Vec<SentenceTransition>>();
                    t.sort_by(|a,b| Ord::cmp(&a.offset,&b.offset));
                    t
                },
                syllable_options: s.syllable_options.or_syllable_options(other.syllable_options.as_ref()),
                display_logo: s.display_logo.or(other.display_logo),
                transition_time_after: s.transition_time_after.or(other.transition_time_after),
                fade_time_after: s.fade_time_after.or(other.fade_time_after),
                transition_time_before: s.transition_time_before.or(other.transition_time_before),
                fade_time_before: s.fade_time_before.or(other.fade_time_before),
                row_position: s.row_position.or(other.row_position),
                size: s.size.or(other.size),
            }),
            (Some(s),None) => Some(s.clone()),
            (None,Some(other)) => Some(other.clone()),
            (None,None) => None
        }
    }
    fn as_syllable_options(&self, offset: i32) -> Option<SyllableOptions> {
        match self.as_sentence_options() {
            None => None,
            Some(sentence_options) => sentence_options.merge_at(offset).syllable_options
        }
    }
}

impl SentenceOptions {
    fn bare(&self) -> SentenceOptions {
        SentenceOptions {
            transitions: Vec::new(),
            syllable_options: self.syllable_options,
            display_logo: self.display_logo,
            transition_time_after: self.transition_time_after,
            fade_time_after: self.fade_time_after,
            transition_time_before: self.transition_time_before,
            fade_time_before: self.fade_time_before,
            row_position: self.row_position,
            size: self.size
        }
    }

    pub fn merge_at(&self, offset: i32) -> SentenceOptions {
        let mut sentence_options = Some(self.bare());
        let iter = self.transitions.iter()
            .take_while(|t| t.offset <= offset);
        for s in iter {
            sentence_options = s.new_options.or_sentence_options(sentence_options.as_ref());
        };
        sentence_options.unwrap()
    }
}

impl AsSentenceOptions for Sentence {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        self.sentence_options.as_ref()
    }
}

impl AsSentenceOptions for Subtitles {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        self.subtitles_options.sentence_options.as_ref()
    }
}

impl AsSentenceOptions for SentenceOptions {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        Some(self)
    }
}

impl AsSentenceOptions for SubtitlesOptions {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        self.sentence_options.as_ref()
    }
}

impl<T:AsSentenceOptions> AsSentenceOptions for Option<T> {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        match *self {
            Some(ref t) => t.as_sentence_options(),
            None => None
        }
    }
}

impl Sentence {
    /// used mainly for debugging purposes
    #[allow(dead_code)]
    pub fn text(&self) -> String {
        self.syllables.iter().fold(String::new(),|mut string,syllable| {
            string.push_str(&*syllable.text);
            string
        })
    }
}

#[derive(Debug,Clone,Default,Serialize,Deserialize)]
pub struct SentenceOptions {
    /// Global SyllableOptions
    #[serde(skip_serializing_if="Option::is_none")]
    pub syllable_options: Option<SyllableOptions>,
    #[serde(default,skip_serializing_if="Vec::is_empty")]
    pub transitions: Vec<SentenceTransition>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub display_logo: Option<bool>,
    /// Total time where subtitles start appearing, before first syllable start playing
    #[serde(skip_serializing_if="Option::is_none")]
    pub transition_time_before: Option<u16>,
    /// Span where subtitles start appearing
    #[serde(skip_serializing_if="Option::is_none")]
    pub fade_time_before: Option<u16>,
    /// Total time where subtitles are disappearing, before first syllable start playing
    #[serde(skip_serializing_if="Option::is_none")]
    pub transition_time_after: Option<u16>,
    /// Span where subtitles start disappearing
    #[serde(skip_serializing_if="Option::is_none")]
    pub fade_time_after: Option<u16>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename = "position")]
    pub row_position: Option<RowPosition>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub size: Option<Size<Option<f32>>>
}

impl Deref for SentenceOptions {
    type Target = Option<SyllableOptions>;
    fn deref(&self) -> &Option<SyllableOptions> {
        &self.syllable_options
    }
}

#[derive(Debug,Clone,Default,Serialize,Deserialize)]
pub struct SentenceTransition {
    pub offset: i32,
    pub new_options: SentenceOptions
}

#[derive(Debug,Clone)]
pub struct SentenceParameters {
    pub display_logo: bool,
    pub transition_time_before: u16,
    pub fade_time_before: u16,
    pub transition_time_after: u16,
    pub fade_time_after: u16,
    pub row_position: Option<RowPosition>,
    pub size:Size<Option<f32>>
}

impl From<(SentenceOptions,i32)> for SentenceParameters {
    fn from((sentence_options, time_offset): (SentenceOptions,i32)) -> Self {
        let sentence_options : SentenceOptions = sentence_options.merge_at(time_offset);
        SentenceParameters {
            display_logo: sentence_options.display_logo.unwrap_or(true),
            transition_time_before: sentence_options.transition_time_before.unwrap_or(800),
            fade_time_before: sentence_options.fade_time_before.unwrap_or(200),
            transition_time_after: sentence_options.transition_time_after.unwrap_or(500),
            fade_time_after: sentence_options.fade_time_after.unwrap_or(200),
            row_position: sentence_options.row_position,
            size: sentence_options.size.unwrap_or(Size {
                width:Some(0.95),
                height:Some(0.09)
            })
        }
    }
}

#[test]
fn test_sentence_options_propagation(){
    use super::*;
    use utils::RGB;
    let default_options = SentenceOptions {
        syllable_options: Some(SyllableOptions {
            alive_color: Some(Color::new(128,0,0)),
            dead_color: Some(Color::new(0,128,0)),
            transition_color: None,
            outline: None
        }),
        ..SentenceOptions::default()
    };
    let syllable_options = SyllableOptions {
        alive_color: Some(Color::new(172,172,172)),
        ..SyllableOptions::default()
    };
    let syllable_parameters = SyllableParameters::from(syllable_options.or_syllable_options(default_options.as_syllable_options()).unwrap());
    assert_eq!(syllable_parameters.alive_color,Color::new(172,172,172));
    assert_eq!(syllable_parameters.dead_color,Color::new(0,128,0));
    assert_eq!(syllable_parameters.transition_color,Color::new(255,0,0));
}
<commit_msg>Fix crash when size.w .h were both null in json<commit_after>use super::{Syllable,SyllableOptions,Subtitles,SubtitlesOptions,AsSyllableOptions};
use super::pos::{RowPosition,Size};
use std::ops::Deref;

#[derive(Debug,Serialize,Deserialize,Clone)]
pub struct Sentence {
    pub syllables: Vec<Syllable>,
    #[serde(skip_serializing,skip_deserializing)]
    pub position: RowPosition,
    #[serde(skip_serializing_if="Option::is_none")]
    pub sentence_options: Option<SentenceOptions>,
}

pub trait AsSentenceOptions {
    fn as_sentence_options(&self) -> Option<&SentenceOptions>;
    fn or_sentence_options(&self,other:Option<&SentenceOptions>) -> Option<SentenceOptions> {
        match (self.as_sentence_options(),other) {
            (Some(s),Some(other)) => Some(SentenceOptions {
                transitions: {
                    use std::cmp::Ord;
                    let mut t = s.transitions.iter()
                        .chain(other.transitions.iter())
                        .cloned()
                        .collect::<Vec<SentenceTransition>>();
                    t.sort_by(|a,b| Ord::cmp(&a.offset,&b.offset));
                    t
                },
                syllable_options: s.syllable_options.or_syllable_options(other.syllable_options.as_ref()),
                display_logo: s.display_logo.or(other.display_logo),
                transition_time_after: s.transition_time_after.or(other.transition_time_after),
                fade_time_after: s.fade_time_after.or(other.fade_time_after),
                transition_time_before: s.transition_time_before.or(other.transition_time_before),
                fade_time_before: s.fade_time_before.or(other.fade_time_before),
                row_position: s.row_position.or(other.row_position),
                size: s.size.or(other.size),
            }),
            (Some(s),None) => Some(s.clone()),
            (None,Some(other)) => Some(other.clone()),
            (None,None) => None
        }
    }
    fn as_syllable_options(&self, offset: i32) -> Option<SyllableOptions> {
        match self.as_sentence_options() {
            None => None,
            Some(sentence_options) => sentence_options.merge_at(offset).syllable_options
        }
    }
}

impl SentenceOptions {
    fn bare(&self) -> SentenceOptions {
        SentenceOptions {
            transitions: Vec::new(),
            syllable_options: self.syllable_options,
            display_logo: self.display_logo,
            transition_time_after: self.transition_time_after,
            fade_time_after: self.fade_time_after,
            transition_time_before: self.transition_time_before,
            fade_time_before: self.fade_time_before,
            row_position: self.row_position,
            size: self.size
        }
    }

    pub fn merge_at(&self, offset: i32) -> SentenceOptions {
        let mut sentence_options = Some(self.bare());
        let iter = self.transitions.iter()
            .take_while(|t| t.offset <= offset);
        for s in iter {
            sentence_options = s.new_options.or_sentence_options(sentence_options.as_ref());
        };
        sentence_options.unwrap()
    }
}

impl AsSentenceOptions for Sentence {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        self.sentence_options.as_ref()
    }
}

impl AsSentenceOptions for Subtitles {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        self.subtitles_options.sentence_options.as_ref()
    }
}

impl AsSentenceOptions for SentenceOptions {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        Some(self)
    }
}

impl AsSentenceOptions for SubtitlesOptions {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        self.sentence_options.as_ref()
    }
}

impl<T:AsSentenceOptions> AsSentenceOptions for Option<T> {
    fn as_sentence_options(&self) -> Option<&SentenceOptions> {
        match *self {
            Some(ref t) => t.as_sentence_options(),
            None => None
        }
    }
}

impl Sentence {
    /// used mainly for debugging purposes
    #[allow(dead_code)]
    pub fn text(&self) -> String {
        self.syllables.iter().fold(String::new(),|mut string,syllable| {
            string.push_str(&*syllable.text);
            string
        })
    }
}

#[derive(Debug,Clone,Default,Serialize,Deserialize)]
pub struct SentenceOptions {
    /// Global SyllableOptions
    #[serde(skip_serializing_if="Option::is_none")]
    pub syllable_options: Option<SyllableOptions>,
    #[serde(default,skip_serializing_if="Vec::is_empty")]
    pub transitions: Vec<SentenceTransition>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub display_logo: Option<bool>,
    /// Total time where subtitles start appearing, before first syllable start playing
    #[serde(skip_serializing_if="Option::is_none")]
    pub transition_time_before: Option<u16>,
    /// Span where subtitles start appearing
    #[serde(skip_serializing_if="Option::is_none")]
    pub fade_time_before: Option<u16>,
    /// Total time where subtitles are disappearing, before first syllable start playing
    #[serde(skip_serializing_if="Option::is_none")]
    pub transition_time_after: Option<u16>,
    /// Span where subtitles start disappearing
    #[serde(skip_serializing_if="Option::is_none")]
    pub fade_time_after: Option<u16>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename = "position")]
    pub row_position: Option<RowPosition>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub size: Option<Size<Option<f32>>>
}

impl Deref for SentenceOptions {
    type Target = Option<SyllableOptions>;
    fn deref(&self) -> &Option<SyllableOptions> {
        &self.syllable_options
    }
}

#[derive(Debug,Clone,Default,Serialize,Deserialize)]
pub struct SentenceTransition {
    pub offset: i32,
    pub new_options: SentenceOptions
}

#[derive(Debug,Clone)]
pub struct SentenceParameters {
    pub display_logo: bool,
    pub transition_time_before: u16,
    pub fade_time_before: u16,
    pub transition_time_after: u16,
    pub fade_time_after: u16,
    pub row_position: Option<RowPosition>,
    pub size:Size<Option<f32>>
}

impl From<(SentenceOptions,i32)> for SentenceParameters {
    fn from((sentence_options, time_offset): (SentenceOptions,i32)) -> Self {
        let sentence_options : SentenceOptions = sentence_options.merge_at(time_offset);
        SentenceParameters {
            display_logo: sentence_options.display_logo.unwrap_or(true),
            transition_time_before: sentence_options.transition_time_before.unwrap_or(800),
            fade_time_before: sentence_options.fade_time_before.unwrap_or(200),
            transition_time_after: sentence_options.transition_time_after.unwrap_or(500),
            fade_time_after: sentence_options.fade_time_after.unwrap_or(200),
            row_position: sentence_options.row_position,
            size: match sentence_options.size {
                None | Some( Size { width:None,height:None}) => Size {
                    width:Some(0.95),
                    height:Some(0.09)
                },
                Some(e) => e
            }
        }
    }
}

#[test]
fn test_sentence_options_propagation(){
    use super::*;
    use utils::RGB;
    let default_options = SentenceOptions {
        syllable_options: Some(SyllableOptions {
            alive_color: Some(Color::new(128,0,0)),
            dead_color: Some(Color::new(0,128,0)),
            transition_color: None,
            outline: None
        }),
        ..SentenceOptions::default()
    };
    let syllable_options = SyllableOptions {
        alive_color: Some(Color::new(172,172,172)),
        ..SyllableOptions::default()
    };
    let syllable_parameters = SyllableParameters::from(syllable_options.or_syllable_options(default_options.as_syllable_options()).unwrap());
    assert_eq!(syllable_parameters.alive_color,Color::new(172,172,172));
    assert_eq!(syllable_parameters.dead_color,Color::new(0,128,0));
    assert_eq!(syllable_parameters.transition_color,Color::new(255,0,0));
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;
use core::fmt::Debug;
use core::usize;

use bytes::{Buf, BufMut};

use crate::encoding::{
    decode_key, encode_varint, encoded_len_varint, message, DecodeContext, WireType,
};
use crate::DecodeError;
use crate::EncodeError;

/// A Protocol Buffers message.
pub trait Message: Debug + Send + Sync {
    /// Encodes the message to a buffer.
    ///
    /// This method will panic if the buffer has insufficient capacity.
    ///
    /// Meant to be used only by `Message` implementations.
    #[doc(hidden)]
    fn encode_raw<B>(&self, buf: &mut B)
    where
        B: BufMut,
        Self: Sized;

    /// Decodes a field from a buffer, and merges it into `self`.
    ///
    /// Meant to be used only by `Message` implementations.
    #[doc(hidden)]
    fn merge_field<B>(
        &mut self,
        tag: u32,
        wire_type: WireType,
        buf: &mut B,
        ctx: DecodeContext,
    ) -> Result<(), DecodeError>
    where
        B: Buf,
        Self: Sized;

    /// Returns the encoded length of the message without a length delimiter.
    fn encoded_len(&self) -> usize;

    /// Encodes the message to a buffer.
    ///
    /// An error will be returned if the buffer does not have sufficient capacity.
    fn encode<B>(&self, buf: &mut B) -> Result<(), EncodeError>
    where
        B: BufMut,
        Self: Sized,
    {
        let required = self.encoded_len();
        let remaining = buf.remaining_mut();
        if required > buf.remaining_mut() {
            return Err(EncodeError::new(required, remaining));
        }

        self.encode_raw(buf);
        Ok(())
    }

    /// Encodes the message with a length-delimiter to a buffer.
    ///
    /// An error will be returned if the buffer does not have sufficient capacity.
    fn encode_length_delimited<B>(&self, buf: &mut B) -> Result<(), EncodeError>
    where
        B: BufMut,
        Self: Sized,
    {
        let len = self.encoded_len();
        let required = len + encoded_len_varint(len as u64);
        let remaining = buf.remaining_mut();
        if required > remaining {
            return Err(EncodeError::new(required, remaining));
        }
        encode_varint(len as u64, buf);
        self.encode_raw(buf);
        Ok(())
    }

    /// Decodes an instance of the message from a buffer.
    ///
    /// The entire buffer will be consumed.
    fn decode<B>(mut buf: B) -> Result<Self, DecodeError>
    where
        B: Buf,
        Self: Default,
    {
        let mut message = Self::default();
        Self::merge(&mut message, &mut buf).map(|_| message)
    }

    /// Decodes a length-delimited instance of the message from the buffer.
    fn decode_length_delimited<B>(buf: B) -> Result<Self, DecodeError>
    where
        B: Buf,
        Self: Default,
    {
        let mut message = Self::default();
        message.merge_length_delimited(buf)?;
        Ok(message)
    }

    /// Decodes an instance of the message from a buffer, and merges it into `self`.
    ///
    /// The entire buffer will be consumed.
    fn merge<B>(&mut self, mut buf: B) -> Result<(), DecodeError>
    where
        B: Buf,
        Self: Sized,
    {
        let ctx = DecodeContext::default();
        while buf.has_remaining() {
            let (tag, wire_type) = decode_key(&mut buf)?;
            self.merge_field(tag, wire_type, &mut buf, ctx.clone())?;
        }
        Ok(())
    }

    /// Decodes a length-delimited instance of the message from buffer, and
    /// merges it into `self`.
    fn merge_length_delimited<B>(&mut self, mut buf: B) -> Result<(), DecodeError>
    where
        B: Buf,
        Self: Sized,
    {
        message::merge(
            WireType::LengthDelimited,
            self,
            &mut buf,
            DecodeContext::default(),
        )
    }

    /// Clears the message, resetting all fields to their default.
    fn clear(&mut self);
}

impl<M> Message for Box<M>
where
    M: Message,
{
    fn encode_raw<B>(&self, buf: &mut B)
    where
        B: BufMut,
    {
        (**self).encode_raw(buf)
    }
    fn merge_field<B>(
        &mut self,
        tag: u32,
        wire_type: WireType,
        buf: &mut B,
        ctx: DecodeContext,
    ) -> Result<(), DecodeError>
    where
        B: Buf,
    {
        (**self).merge_field(tag, wire_type, buf, ctx)
    }
    fn encoded_len(&self) -> usize {
        (**self).encoded_len()
    }
    fn clear(&mut self) {
        (**self).clear()
    }
}
<commit_msg>Add test to assert that Message is object safe<commit_after>use alloc::boxed::Box;
use core::fmt::Debug;
use core::usize;

use bytes::{Buf, BufMut};

use crate::encoding::{
    decode_key, encode_varint, encoded_len_varint, message, DecodeContext, WireType,
};
use crate::DecodeError;
use crate::EncodeError;

/// A Protocol Buffers message.
pub trait Message: Debug + Send + Sync {
    /// Encodes the message to a buffer.
    ///
    /// This method will panic if the buffer has insufficient capacity.
    ///
    /// Meant to be used only by `Message` implementations.
    #[doc(hidden)]
    fn encode_raw<B>(&self, buf: &mut B)
    where
        B: BufMut,
        Self: Sized;

    /// Decodes a field from a buffer, and merges it into `self`.
    ///
    /// Meant to be used only by `Message` implementations.
    #[doc(hidden)]
    fn merge_field<B>(
        &mut self,
        tag: u32,
        wire_type: WireType,
        buf: &mut B,
        ctx: DecodeContext,
    ) -> Result<(), DecodeError>
    where
        B: Buf,
        Self: Sized;

    /// Returns the encoded length of the message without a length delimiter.
    fn encoded_len(&self) -> usize;

    /// Encodes the message to a buffer.
    ///
    /// An error will be returned if the buffer does not have sufficient capacity.
    fn encode<B>(&self, buf: &mut B) -> Result<(), EncodeError>
    where
        B: BufMut,
        Self: Sized,
    {
        let required = self.encoded_len();
        let remaining = buf.remaining_mut();
        if required > buf.remaining_mut() {
            return Err(EncodeError::new(required, remaining));
        }

        self.encode_raw(buf);
        Ok(())
    }

    /// Encodes the message with a length-delimiter to a buffer.
    ///
    /// An error will be returned if the buffer does not have sufficient capacity.
    fn encode_length_delimited<B>(&self, buf: &mut B) -> Result<(), EncodeError>
    where
        B: BufMut,
        Self: Sized,
    {
        let len = self.encoded_len();
        let required = len + encoded_len_varint(len as u64);
        let remaining = buf.remaining_mut();
        if required > remaining {
            return Err(EncodeError::new(required, remaining));
        }
        encode_varint(len as u64, buf);
        self.encode_raw(buf);
        Ok(())
    }

    /// Decodes an instance of the message from a buffer.
    ///
    /// The entire buffer will be consumed.
    fn decode<B>(mut buf: B) -> Result<Self, DecodeError>
    where
        B: Buf,
        Self: Default,
    {
        let mut message = Self::default();
        Self::merge(&mut message, &mut buf).map(|_| message)
    }

    /// Decodes a length-delimited instance of the message from the buffer.
    fn decode_length_delimited<B>(buf: B) -> Result<Self, DecodeError>
    where
        B: Buf,
        Self: Default,
    {
        let mut message = Self::default();
        message.merge_length_delimited(buf)?;
        Ok(message)
    }

    /// Decodes an instance of the message from a buffer, and merges it into `self`.
    ///
    /// The entire buffer will be consumed.
    fn merge<B>(&mut self, mut buf: B) -> Result<(), DecodeError>
    where
        B: Buf,
        Self: Sized,
    {
        let ctx = DecodeContext::default();
        while buf.has_remaining() {
            let (tag, wire_type) = decode_key(&mut buf)?;
            self.merge_field(tag, wire_type, &mut buf, ctx.clone())?;
        }
        Ok(())
    }

    /// Decodes a length-delimited instance of the message from buffer, and
    /// merges it into `self`.
    fn merge_length_delimited<B>(&mut self, mut buf: B) -> Result<(), DecodeError>
    where
        B: Buf,
        Self: Sized,
    {
        message::merge(
            WireType::LengthDelimited,
            self,
            &mut buf,
            DecodeContext::default(),
        )
    }

    /// Clears the message, resetting all fields to their default.
    fn clear(&mut self);
}

impl<M> Message for Box<M>
where
    M: Message,
{
    fn encode_raw<B>(&self, buf: &mut B)
    where
        B: BufMut,
    {
        (**self).encode_raw(buf)
    }
    fn merge_field<B>(
        &mut self,
        tag: u32,
        wire_type: WireType,
        buf: &mut B,
        ctx: DecodeContext,
    ) -> Result<(), DecodeError>
    where
        B: Buf,
    {
        (**self).merge_field(tag, wire_type, buf, ctx)
    }
    fn encoded_len(&self) -> usize {
        (**self).encoded_len()
    }
    fn clear(&mut self) {
        (**self).clear()
    }
}

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

    const _MESSAGE_IS_OBJECT_SAFE: Option<&dyn Message> = None;
}
<|endoftext|>


<commit_before>use std::{iter, thread};
use std::sync::atomic::{AtomicIsize, AtomicBool, Ordering};
use std::time::Duration;
use rand::{Rng, XorShiftRng};
use crossbeam;
use crossbeam::sync::MsQueue;
use config;
use player::Player;
use field::{Pos, Field};
use trajectories_pruning::TrajectoriesPruning;
use common;

const MINIMAX_STR: &'static str = "minimax";

fn alpha_beta<T: Rng>(field: &mut Field, depth: u32, last_pos: Pos, player: Player, trajectories_pruning: &TrajectoriesPruning, mut alpha: i32, beta: i32, empty_board: &mut Vec<u32>, rng: &mut T, should_stop: &AtomicBool) -> i32 {
  let enemy = player.next();
  if common::is_last_move_stupid(field, last_pos, enemy) {
    return i32::max_value();
  }
  if depth == 0 {
    return field.score(player);
  }
  let moves = trajectories_pruning.moves();
  if moves.is_empty() {
    return field.score(player);
  }
  for &pos in moves {
    if should_stop.load(Ordering::Relaxed) {
      break;
    }
    field.put_point(pos, player);
    if common::is_penult_move_stuped(field) {
      field.undo();
      return i32::max_value();
    }
    let next_trajectories_pruning = TrajectoriesPruning::from_last(field, enemy, depth - 1, empty_board, rng, trajectories_pruning, pos, should_stop);
    let mut cur_estimation = -alpha_beta(field, depth - 1, pos, enemy, &next_trajectories_pruning, -alpha - 1, -alpha, empty_board, rng, should_stop);
    if cur_estimation > alpha && cur_estimation < beta {
      cur_estimation = -alpha_beta(field, depth - 1, pos, enemy, &next_trajectories_pruning, -beta, -cur_estimation, empty_board, rng, should_stop);
    }
    field.undo();
    if cur_estimation > alpha {
      alpha = cur_estimation;
      if alpha >= beta {
        break;
      }
    }
  }
  alpha
}

fn alpha_beta_parallel<T: Rng>(field: &mut Field, player: Player, depth: u32, alpha: i32, beta: i32, trajectories_pruning: &TrajectoriesPruning, rng: &mut T, best_move: &mut Option<Pos>, should_stop: &AtomicBool) -> i32 {
  info!(target: MINIMAX_STR, "Starting parellel alpha beta with depth {}, player {} and beta {}.", depth, player, beta);
  if depth == 0 || should_stop.load(Ordering::Relaxed) {
    *best_move = None;
    return field.score(player);
  }
  let moves = trajectories_pruning.moves();
  debug!(target: MINIMAX_STR, "Moves in consideration: {:?}.", moves.iter().map(|&pos| (field.to_x(pos), field.to_y(pos))).collect::<Vec<(u32, u32)>>());
  if moves.is_empty() || should_stop.load(Ordering::Relaxed) {
    *best_move = None;
    return field.score(player);
  }
  let queue = MsQueue::new();
  if let Some(best_pos) = *best_move {
    queue.push(best_pos);
    for &pos in moves.iter().filter(|&&pos| pos != best_pos) {
      queue.push(pos);
    }
  } else {
    for &pos in moves.iter() {
      queue.push(pos);
    }
  }
  let threads_count = config::threads_count();
  let atomic_alpha = AtomicIsize::new(alpha as isize);
  let best_moves = MsQueue::new();
  crossbeam::scope(|scope| {
    for _ in 0 .. threads_count {
      let xor_shift_rng = rng.gen::<XorShiftRng>();
      scope.spawn(|| {
        let mut local_field = field.clone();
        let mut local_rng = xor_shift_rng;
        let mut local_empty_board = iter::repeat(0u32).take(field.length()).collect();
        let mut local_best_move = 0;
        let mut local_alpha = alpha;
        let enemy = player.next();
        while let Some(pos) = queue.try_pop() {
          if should_stop.load(Ordering::Relaxed) {
            break;
          }
          local_field.put_point(pos, player);
          let next_trajectories_pruning = TrajectoriesPruning::from_last(&mut local_field, enemy, depth - 1, &mut local_empty_board, &mut local_rng, trajectories_pruning, pos, should_stop);
          if should_stop.load(Ordering::Relaxed) {
            break;
          }
          let cur_alpha = atomic_alpha.load(Ordering::Relaxed) as i32;
          if cur_alpha >= beta {
            break;
          }
          let mut cur_estimation = -alpha_beta(&mut local_field, depth - 1, pos, enemy, &next_trajectories_pruning, -cur_alpha - 1, -cur_alpha, &mut local_empty_board, &mut local_rng, should_stop);
          if cur_estimation > cur_alpha && !should_stop.load(Ordering::Relaxed) {
            cur_estimation = -alpha_beta(&mut local_field, depth - 1, pos, enemy, &next_trajectories_pruning, -beta, -cur_estimation, &mut local_empty_board, &mut local_rng, should_stop);
          }
          debug!(target: MINIMAX_STR, "Estimation for move ({}, {}) is {}, alpha is {}, beta is {}.", field.to_x(pos), field.to_y(pos), cur_estimation, cur_alpha, beta);
          local_field.undo();
          if cur_estimation > cur_alpha {
            local_alpha = cur_estimation;
            local_best_move = pos;
          }
          loop {
            let last_alpha = atomic_alpha.load(Ordering::Relaxed);
            if cur_estimation <= last_alpha as i32 || atomic_alpha.compare_and_swap(last_alpha, cur_estimation as isize, Ordering::Relaxed) == last_alpha {
              break;
            }
          }
        }
        if local_best_move != 0 && local_alpha == atomic_alpha.load(Ordering::Relaxed) as i32 {
          best_moves.push((local_best_move, local_alpha));
        }
      });
    }
  });
  let mut result = 0;
  let best_alpha = atomic_alpha.load(Ordering::Relaxed) as i32;
  while let Some((pos, pos_alpha)) = best_moves.try_pop() {
    if pos_alpha == best_alpha {
      result = pos;
      break;
    }
  }
  if result == 0 {
    info!(target: MINIMAX_STR, "Best move is not found.");
    *best_move = None;
  } else {
    info!(target: MINIMAX_STR, "Best move is ({}, {}).", field.to_x(result), field.to_y(result));
    *best_move = Some(result);
  }
  let cur_alpha = atomic_alpha.load(Ordering::SeqCst);
  info!(target: MINIMAX_STR, "Estimation is {}.", cur_alpha);
  cur_alpha as i32
}

pub fn minimax<T: Rng>(field: &mut Field, player: Player, rng: &mut T, depth: u32) -> Option<Pos> {
  info!(target: MINIMAX_STR, "Starting minimax with depth {} and player {}.", depth, player);
  if depth == 0 {
    return None;
  }
  let should_stop = AtomicBool::new(false);
  let mut empty_board = iter::repeat(0u32).take(field.length()).collect();
  let trajectories_pruning = TrajectoriesPruning::new(field, player, depth, &mut empty_board, rng, &should_stop);
  let mut best_move = None;
  info!(target: MINIMAX_STR, "Calculating of our estimation. Player is {}", player);
  let estimation = alpha_beta_parallel(field, player, depth, i32::min_value() + 1, i32::max_value(), &trajectories_pruning, rng, &mut best_move, &should_stop);
  let enemy = player.next();
  let mut enemy_best_move = best_move;
  let enemy_trajectories_pruning = TrajectoriesPruning::dec_and_swap_exists(field, depth - 1, &mut empty_board, rng, &trajectories_pruning, &should_stop);
  info!(target: MINIMAX_STR, "Calculating of enemy estimation with upper bound {}. Player is {}", -estimation + 1, enemy);
  if -alpha_beta_parallel(field, enemy, depth - 1, -estimation, -estimation + 1, &enemy_trajectories_pruning, rng, &mut enemy_best_move, &should_stop) < estimation {
    info!(target: MINIMAX_STR,  "Estimation is greater than enemy estimation. So the best move is {:?}, estimation is {}.", best_move.map(|pos| (field.to_x(pos), field.to_y(pos))), estimation);
    best_move
  } else {
    info!(target: MINIMAX_STR,  "Estimation is less than or equal enemy estimation. So all moves have the same estimation {}.", estimation);
    None
  }
}

pub fn minimax_with_time<T: Rng>(field: &mut Field, player: Player, rng: &mut T, time: u32) -> Option<Pos> {
  let should_stop = AtomicBool::new(false);
  crossbeam::scope(|scope| {
    scope.spawn(|| {
      thread::sleep(Duration::from_millis(time as u64));
      debug!(target: MINIMAX_STR, "Time-out!");
      should_stop.store(true, Ordering::Relaxed);
    });
    let enemy = player.next();
    let mut depth = 1;
    let mut best_move = None;
    let mut cur_best_move = None;
    let mut enemy_best_move = None;
    let mut empty_board = iter::repeat(0u32).take(field.length()).collect();
    let mut trajectories_pruning = TrajectoriesPruning::new(field, player, depth, &mut empty_board, rng, &should_stop);
    while !should_stop.load(Ordering::Relaxed) {
      let estimation = alpha_beta_parallel(field, player, depth, i32::min_value() + 1, i32::max_value(), &trajectories_pruning, rng, &mut cur_best_move, &should_stop);
      if should_stop.load(Ordering::Relaxed) { //TODO: use calculated move.
        break;
      }
      let enemy_trajectories_pruning = TrajectoriesPruning::dec_and_swap_exists(field, depth - 1, &mut empty_board, rng, &trajectories_pruning, &should_stop);
      if should_stop.load(Ordering::Relaxed) {
        break;
      }
      best_move = if -alpha_beta_parallel(field, enemy, depth - 1, -estimation, -estimation + 1, &enemy_trajectories_pruning, rng, &mut enemy_best_move, &should_stop) < estimation || should_stop.load(Ordering::Relaxed) {
        cur_best_move
      } else {
        None
      };
      if should_stop.load(Ordering::Relaxed) {
        break;
      }
      depth += 1;
      trajectories_pruning = TrajectoriesPruning::inc_exists(field, player, depth, &mut empty_board, rng, &trajectories_pruning, &should_stop);
    }
    best_move
  })
}
<commit_msg>Minimax with time improvements.<commit_after>use std::{iter, thread};
use std::sync::atomic::{AtomicIsize, AtomicBool, Ordering};
use std::time::Duration;
use rand::{Rng, XorShiftRng};
use crossbeam;
use crossbeam::sync::MsQueue;
use config;
use player::Player;
use field::{Pos, Field};
use trajectories_pruning::TrajectoriesPruning;
use common;

const MINIMAX_STR: &'static str = "minimax";

fn alpha_beta<T: Rng>(
  field: &mut Field,
  depth: u32,
  last_pos: Pos,
  player: Player,
  trajectories_pruning: &TrajectoriesPruning,
  mut alpha: i32,
  beta: i32,
  empty_board: &mut Vec<u32>,
  rng: &mut T,
  should_stop: &AtomicBool
) -> i32 {
  let enemy = player.next();
  if common::is_last_move_stupid(field, last_pos, enemy) {
    return i32::max_value();
  }
  if depth == 0 {
    return field.score(player);
  }
  let moves = trajectories_pruning.moves();
  if moves.is_empty() {
    return field.score(player);
  }
  for &pos in moves {
    if should_stop.load(Ordering::Relaxed) {
      break;
    }
    field.put_point(pos, player);
    if common::is_penult_move_stuped(field) {
      field.undo();
      return i32::max_value();
    }
    let next_trajectories_pruning = TrajectoriesPruning::from_last(
      field,
      enemy,
      depth - 1,
      empty_board,
      rng,
      trajectories_pruning,
      pos,
      should_stop
    );
    let mut cur_estimation = -alpha_beta(
      field,
      depth - 1,
      pos,
      enemy,
      &next_trajectories_pruning,
      -alpha - 1,
      -alpha,
      empty_board,
      rng,
      should_stop
    );
    if cur_estimation > alpha && cur_estimation < beta {
      cur_estimation = -alpha_beta(
        field,
        depth - 1,
        pos,
        enemy,
        &next_trajectories_pruning,
        -beta,
        -cur_estimation,
        empty_board,
        rng,
        should_stop
      );
    }
    field.undo();
    if cur_estimation > alpha {
      alpha = cur_estimation;
      if alpha >= beta {
        break;
      }
    }
  }
  alpha
}

fn alpha_beta_parallel<T: Rng>(
  field: &mut Field,
  player: Player,
  depth: u32,
  alpha: i32,
  beta: i32,
  trajectories_pruning: &TrajectoriesPruning,
  rng: &mut T,
  best_move: &mut Option<Pos>,
  should_stop: &AtomicBool
) -> i32 {
  info!(
    target: MINIMAX_STR,
    "Starting parellel alpha beta with depth {}, player {} and beta {}.",
    depth,
    player,
    beta
  );
  if depth == 0 || should_stop.load(Ordering::Relaxed) {
    *best_move = None;
    return field.score(player);
  }
  let moves = trajectories_pruning.moves();
  debug!(
    target: MINIMAX_STR,
    "Moves in consideration: {:?}.",
    moves.iter().map(|&pos| (field.to_x(pos), field.to_y(pos))).collect::<Vec<(u32, u32)>>()
  );
  if moves.is_empty() || should_stop.load(Ordering::Relaxed) {
    *best_move = None;
    return field.score(player);
  }
  let queue = MsQueue::new();
  if let Some(best_pos) = *best_move {
    queue.push(best_pos);
    for &pos in moves.iter().filter(|&&pos| pos != best_pos) {
      queue.push(pos);
    }
  } else {
    for &pos in moves.iter() {
      queue.push(pos);
    }
  }
  let threads_count = config::threads_count();
  let atomic_alpha = AtomicIsize::new(alpha as isize);
  let best_moves = MsQueue::new();
  crossbeam::scope(|scope| {
    for _ in 0 .. threads_count {
      let xor_shift_rng = rng.gen::<XorShiftRng>();
      scope.spawn(|| {
        let mut local_field = field.clone();
        let mut local_rng = xor_shift_rng;
        let mut local_empty_board = iter::repeat(0u32).take(field.length()).collect();
        let mut local_best_move = 0;
        let mut local_alpha = alpha;
        let enemy = player.next();
        while let Some(pos) = queue.try_pop() {
          if should_stop.load(Ordering::Relaxed) {
            break;
          }
          local_field.put_point(pos, player);
          let next_trajectories_pruning = TrajectoriesPruning::from_last(
            &mut local_field,
            enemy,
            depth - 1,
            &mut local_empty_board,
            &mut local_rng,
            trajectories_pruning,
            pos,
            should_stop
          );
          if should_stop.load(Ordering::Relaxed) {
            break;
          }
          let cur_alpha = atomic_alpha.load(Ordering::Relaxed) as i32;
          if cur_alpha >= beta {
            break;
          }
          let mut cur_estimation = -alpha_beta(
            &mut local_field,
            depth - 1,
            pos,
            enemy,
            &next_trajectories_pruning,
            -cur_alpha - 1,
            -cur_alpha,
            &mut local_empty_board,
            &mut local_rng,
            should_stop
          );
          if cur_estimation > cur_alpha && !should_stop.load(Ordering::Relaxed) {
            cur_estimation = -alpha_beta(
              &mut local_field,
              depth - 1,
              pos,
              enemy,
              &next_trajectories_pruning,
              -beta,
              -cur_estimation,
              &mut local_empty_board,
              &mut local_rng,
              should_stop
            );
          }
          debug!(
            target: MINIMAX_STR,
            "Estimation for move ({}, {}) is {}, alpha is {}, beta is {}.",
            field.to_x(pos),
            field.to_y(pos),
            cur_estimation,
            cur_alpha,
            beta
          );
          local_field.undo();
          if cur_estimation > cur_alpha {
            local_alpha = cur_estimation;
            local_best_move = pos;
          }
          loop {
            let last_alpha = atomic_alpha.load(Ordering::Relaxed);
            if cur_estimation <= last_alpha as i32 || atomic_alpha.compare_and_swap(
              last_alpha,
              cur_estimation as isize,
              Ordering::Relaxed
            ) == last_alpha {
              break;
            }
          }
        }
        if local_best_move != 0 && local_alpha == atomic_alpha.load(Ordering::Relaxed) as i32 {
          best_moves.push((local_best_move, local_alpha));
        }
      });
    }
  });
  let mut result = 0;
  let best_alpha = atomic_alpha.load(Ordering::Relaxed) as i32;
  while let Some((pos, pos_alpha)) = best_moves.try_pop() {
    if pos_alpha == best_alpha {
      result = pos;
      break;
    }
  }
  if result == 0 {
    info!(target: MINIMAX_STR, "Best move is not found.");
    *best_move = None;
  } else {
    info!(target: MINIMAX_STR, "Best move is ({}, {}).", field.to_x(result), field.to_y(result));
    *best_move = Some(result);
  }
  let cur_alpha = atomic_alpha.load(Ordering::SeqCst);
  info!(target: MINIMAX_STR, "Estimation is {}.", cur_alpha);
  cur_alpha as i32
}

pub fn minimax<T: Rng>(field: &mut Field, player: Player, rng: &mut T, depth: u32) -> Option<Pos> {
  info!(target: MINIMAX_STR, "Starting minimax with depth {} and player {}.", depth, player);
  if depth == 0 {
    return None;
  }
  let should_stop = AtomicBool::new(false);
  let mut empty_board = iter::repeat(0u32).take(field.length()).collect();
  let trajectories_pruning = TrajectoriesPruning::new(
    field,
    player,
    depth,
    &mut empty_board,
    rng,
    &should_stop
  );
  let mut best_move = None;
  info!(target: MINIMAX_STR, "Calculating of our estimation. Player is {}", player);
  let estimation = alpha_beta_parallel(
    field,
    player,
    depth,
    i32::min_value() + 1,
    i32::max_value(),
    &trajectories_pruning,
    rng,
    &mut best_move,
    &should_stop
  );
  let enemy = player.next();
  let mut enemy_best_move = best_move;
  let enemy_trajectories_pruning = TrajectoriesPruning::dec_and_swap_exists(
    field,
    depth - 1,
    &mut empty_board,
    rng,
    &trajectories_pruning,
    &should_stop
  );
  info!(
    target: MINIMAX_STR,
    "Calculating of enemy estimation with upper bound {}. Player is {}",
    -estimation + 1,
    enemy
  );
  // Check if we could lose something if we don't make the current best move.
  // If we couldn't that means that the current best move is just a random move.
  if -alpha_beta_parallel(
    field,
    enemy,
    depth - 1,
    -estimation,
    -estimation + 1,
    &enemy_trajectories_pruning,
    rng,
    &mut enemy_best_move,
    &should_stop
  ) < estimation {
    info!(
      target: MINIMAX_STR,
      "Estimation is greater than enemy estimation. So the best move is {:?}, estimation is {}.",
      best_move.map(|pos| (field.to_x(pos), field.to_y(pos))),
      estimation
    );
    best_move
  } else {
    info!(
      target: MINIMAX_STR,
      "Estimation is less than or equal enemy estimation. So all moves have the same estimation {}.",
      estimation
    );
    None
  }
}

pub fn minimax_with_time<T: Rng>(field: &mut Field, player: Player, rng: &mut T, time: u32) -> Option<Pos> {
  let should_stop = AtomicBool::new(false);
  crossbeam::scope(|scope| {
    scope.spawn(|| {
      thread::sleep(Duration::from_millis(time as u64));
      debug!(target: MINIMAX_STR, "Time-out!");
      should_stop.store(true, Ordering::Relaxed);
    });
    let enemy = player.next();
    let mut depth = 1;
    let mut best_move = None;
    let mut cur_best_move = None;
    let mut enemy_best_move = None;
    let mut empty_board = iter::repeat(0u32).take(field.length()).collect();
    let mut trajectories_pruning = TrajectoriesPruning::new(field, player, depth, &mut empty_board, rng, &should_stop);
    while !should_stop.load(Ordering::Relaxed) {
      let estimation = alpha_beta_parallel(
        field,
        player,
        depth,
        i32::min_value() + 1,
        i32::max_value(),
        &trajectories_pruning,
        rng,
        &mut cur_best_move,
        &should_stop
      );
      if should_stop.load(Ordering::Relaxed) {
        // If we found the best move on the previous iteration then the current best move can't be worse than that move.
        // Otherwise it's possible that the current best move is just a random move.
        if !best_move.is_none() {
          best_move = cur_best_move;
        }
        break;
      }
      let enemy_trajectories_pruning = TrajectoriesPruning::dec_and_swap_exists(
        field,
        depth - 1,
        &mut empty_board,
        rng,
        &trajectories_pruning,
        &should_stop
      );
      if should_stop.load(Ordering::Relaxed) {
        // See previous comment.
        if !best_move.is_none() {
          best_move = cur_best_move;
        }
        break;
      }
      // Check if we could lose something if we don't make the current best move.
      // If we couldn't that means that the current best move is just a random move.
      // If we found the best move on previous iteration then likely the current best move is also the best one.
      best_move = if !best_move.is_none() || -alpha_beta_parallel(
        field,
        enemy,
        depth - 1,
        -estimation,
        -estimation + 1,
        &enemy_trajectories_pruning,
        rng,
        &mut enemy_best_move,
        &should_stop
      ) < estimation {
        cur_best_move
      } else {
        None
      };
      if should_stop.load(Ordering::Relaxed) {
        break;
      }
      depth += 1;
      trajectories_pruning = TrajectoriesPruning::inc_exists(
        field,
        player,
        depth,
        &mut empty_board,
        rng,
        &trajectories_pruning,
        &should_stop
      );
    }
    best_move
  })
}
<|endoftext|>


<commit_before>//! Contains code relating to networking.

#[cfg(test)]
mod test;

use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::io;
use std::io::Read;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
use std::thread;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{Receiver, Sender, channel};

use bincode::serde::{DeserializeError, deserialize, serialize};
use bincode::SizeLimit;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};

/// Standard number to ensure network connections are syncronized and the same protocol is being used.
///
/// Reexported incase it is of use for something not-networking.
pub const NET_MAGIC_NUMBER: u32 = 0xCB011043; //0xcafebade + 0x25565, because programming references.

/// The maximum number of clients allowed to be connected at one time.
///
/// Eventually this should be removed and replaced with something configurable.
pub const MAX_CONNECTED_CLIENTS: usize = 30;

/// Holds all state for networking.
///
/// Has no notion of client or server. A client can listen, if that would ever be useful.
#[derive(Debug, Clone)]
pub struct Controller {
    pub raw: Arc<ControllerRaw>,
}

impl Controller {
    /// Contructs a new Controller, without any connection or listeners.
    ///
    /// This spawns a new thread to check multithreading channels.
    pub fn new_empty() -> Controller {
        let (tx, rx) = channel::<ControllerMessage>();
        let self_raw = Arc::from(ControllerRaw {
            connections: RwLock::new(Vec::new()),
            tx: Mutex::new(tx),
        });
        let self_raw_clone = self_raw.clone();
        thread::spawn(move || {
            check_controller_channel(rx, self_raw_clone);
        });
        Controller { raw: self_raw }
    }

    /// Adds a new listener and spins up a new thread to check it.
    ///
    /// The added listener can never be removed, due to the fact that the TcpListener lacks a shutdown method.
    ///
    /// # Errors
    /// * A call to `listener.try_clone()` failed for some reason.
    pub fn add_listener(&mut self, listener: TcpListener) -> Result<(), io::Error> {
        let listener_clone = try!(listener.try_clone());
        let tx_clone = self.raw.tx.lock().unwrap().clone();
        thread::spawn(|| {
            check_listener(listener_clone, tx_clone);
        });
        Ok(())
    }
}

/// Raw representation of a controller. Used internally for things.
#[derive(Debug)]
pub struct ControllerRaw {
    pub connections: RwLock<Vec<Connection>>,
    pub tx: Mutex<Sender<ControllerMessage>>,
}

#[derive(Debug)]
/// Represents a single connection without any notion of client or server.
///
/// It's own struct to allow for hooks and the like.
pub struct Connection {
    pub channel: Mutex<Sender<ConnectionMessage>>,
}

/// Sent in the case of an error that should be sent to the peer.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkError {
    /// If the versions mismatch sufficently to become incompatible with each other.
    VersionMismatch(String, String),
    /// If both peers have should_crash == false, then this error should be sent.
    ///
    /// Do note that this error should not be rewrapped into a reerror, since it would cause a loop.
    /// Instead, it should be logged and ignored, as the connection will be killed shortly after.
    ShouldCrashBothTrue,
}

impl Display for NetworkError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            NetworkError::VersionMismatch(ref ver1, ref ver2) => {
                write!(fmt,
                       "VersionMismatch: The versions of the client and server attempting to \
                        connect mismatch. ver1: {}, ver2: {}",
                       ver1,
                       ver2)
            }
            NetworkError::ShouldCrashBothTrue => {
                write!(fmt,
                       "ShouldCrashBothTrue: Both peers have should_crash == false.")
            }
        }
    }
}

impl Error for NetworkError {
    fn description(&self) -> &str {
        match *self {
            NetworkError::VersionMismatch(_, _) => {
                "VersionMismatch: The versions of the client and server attempting to connect \
                 mismatch."
            }
            NetworkError::ShouldCrashBothTrue => {
                "ShouldCrashBothTrue: Both peers have should_crash == false."
            }
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            NetworkError::VersionMismatch(_, _) => None,
            NetworkError::ShouldCrashBothTrue => None,
        }
    }
}

/// Messages that can be sent between peers to facilitate vairous actions.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkPacket {
    /// Sent on connection to verify everything is in sync.
    Init {
        /// The curent version of the local game.
        ///
        /// Should be formatted according to Scematic Versioning.
        version: String,
        /// If the local game should crash when an error occours.
        ///
        /// Two peers should not have this as false, because should_crash will send the error to the
        /// remote peer and make it crash instead.
        /// This would cause a infinite loop if both were to do it.
        should_crash: bool,
    },
    /// An error that should crash the game and show an error to the user, but only on a client.
    Error(NetworkError),
}

/// Message sent to a connection to do vairous actions.
#[derive(Debug, Clone, Copy)]
pub enum ConnectionMessage {
    DoNothing,
}

/// Channel message sent to controller to dictate certain actions.
#[derive(Debug, Clone)]
pub enum ControllerMessage {
    /// Add a socket, spinning up a new thread in the process.
    AddSocket(Sender<ConnectionMessage>, String),
}

/// Parses a str to a SocketAddr.
///
/// This is a function because while str implements ToSocketAddrs, it requires a good bit of boilerplate to use.
///
/// #Panics
/// * Calling with a localhost ip address: Use 127.0.0.1 instead.
/// * Calling with an ip address that resolves to more than 1 ip address.
pub fn ip(ip_addr: &str) -> SocketAddr {
    if ip_addr.starts_with("localhost") {
        panic!("because localhost can resolve to both 127.0.0.1, and the various IPV6 versions \
                of 127.0.0.1, it may not be used. please instead use 127.0.0.1");
    }
    let mut iter = ip_addr.to_socket_addrs().unwrap();
    let ip = iter.next().unwrap();
    if iter.next() != None {
        panic!("the given ip to net::ip() resolved to more than 1 SocketAddr");
    }
    ip
}

fn check_controller_channel(rx: Receiver<ControllerMessage>, controller: Arc<ControllerRaw>) {
    loop {
        match rx.recv() {
            Ok(msg) => {
                match msg {
                    ControllerMessage::AddSocket(tx_connection, _addr) => {
                        // TODO: Add a hook allowing intersepting the addr and denying the connection.
                        controller.connections
                                  .write()
                                  .unwrap()
                                  .push(Connection { channel: Mutex::new(tx_connection) });
                    }
                }
            }
            Err(_err) => {
                debug!("Channel connected to controller disconnected");
                break;
            }
        }
    }
}

fn check_listener(listener: TcpListener, channel_: Sender<ControllerMessage>) {
    loop {
        match listener.accept() {
            Ok((stream, addr)) => {
                let (tx, rx) = channel();
                match channel_.send(ControllerMessage::AddSocket(tx, addr.to_string())) {
                    Ok(()) => {}
                    Err(_err) => {
                        debug!("listener {:?} stopped accepting because of channel close",
                               listener);
                        break;
                    }
                }
                let stream_clone = stream.try_clone().unwrap();
                thread::spawn(|| check_stream_send(rx, stream));
                thread::spawn(|| check_stream_recv(stream_clone));
            }
            Err(err) => panic!("{}", err),  // TODO: Better handle errors.
        }
    }
}

fn check_stream_send(rx: Receiver<ConnectionMessage>, _stream: TcpStream) {
    loop {
        match rx.recv().unwrap() {
            ConnectionMessage::DoNothing => {},
        }
    }
}

fn check_stream_recv(mut stream: TcpStream) {
    loop {
        let mut header: [u8; 6] = [0; 6];
        (&mut stream).take(6).read_exact(&mut header).unwrap();
        let len = get_packet_length(header).unwrap();
        let mut bytes: Vec<u8> = Vec::new();
        (&mut stream).take(len as u64).read_to_end(&mut bytes).unwrap();    // I think I'm in love.
        let message = deserialize_packet(&bytes).unwrap();
        handle_message(message);
    }
}

fn deserialize_packet(to_de: &[u8]) -> Result<NetworkPacket, DeserializeError> {
    deserialize(to_de)
}

/// Returns the length of a given packet, or a None if the first four bytes do not match NET_MAGIC_NUMBER.
fn get_packet_length(to_ln: [u8; 6]) -> Option<u16> {
    let (first_four, next_two) = to_ln.split_at(4);
    let should_be_magic_num = LittleEndian::read_u32(&first_four);
    if should_be_magic_num != NET_MAGIC_NUMBER {
        return None;
    }
    let length = LittleEndian::read_u16(&next_two);
    Some(length)
}

fn handle_message(_message: NetworkPacket) {
    unimplemented!()
}

#[allow(unused)]
fn seralize_packet(to_ser: &NetworkPacket) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::new();
    result.write_u32::<LittleEndian>(NET_MAGIC_NUMBER).unwrap();   // No possible errors here.
    // The NET_MAGIC_NUMBER is used before every packet, so incase the stream is desynced for whatever reason, the game doesn't just read arbratrary data and crash badly.
    // Instead, it can either recover somehow, by disconnecting and reconnecting, or just erroring gracefully.
    let mut encoded = serialize(to_ser, SizeLimit::Infinite).unwrap();
    // Since the size limit is infinite and i'm not encoding to a stream, there is no error and I can safely unwrap();
    result.write_u16::<LittleEndian>(encoded.len() as u16).unwrap();
    result.append(&mut encoded);
    result
}
<commit_msg>Handle connection resets and interupted errors in net::check_stream_recv<commit_after>//! Contains code relating to networking.

#[cfg(test)]
mod test;

use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::io;
use std::io::Read;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
use std::thread;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{Receiver, Sender, channel};

use bincode::serde::{DeserializeError, deserialize, serialize};
use bincode::SizeLimit;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};

/// Standard number to ensure network connections are syncronized and the same protocol is being used.
///
/// Reexported incase it is of use for something not-networking.
pub const NET_MAGIC_NUMBER: u32 = 0xCB011043; //0xcafebade + 0x25565, because programming references.

/// The maximum number of clients allowed to be connected at one time.
///
/// Eventually this should be removed and replaced with something configurable.
pub const MAX_CONNECTED_CLIENTS: usize = 30;

/// Holds all state for networking.
///
/// Has no notion of client or server. A client can listen, if that would ever be useful.
#[derive(Debug, Clone)]
pub struct Controller {
    pub raw: Arc<ControllerRaw>,
}

impl Controller {
    /// Contructs a new Controller, without any connection or listeners.
    ///
    /// This spawns a new thread to check multithreading channels.
    pub fn new_empty() -> Controller {
        let (tx, rx) = channel::<ControllerMessage>();
        let self_raw = Arc::from(ControllerRaw {
            connections: RwLock::new(Vec::new()),
            tx: Mutex::new(tx),
        });
        let self_raw_clone = self_raw.clone();
        thread::spawn(move || {
            check_controller_channel(rx, self_raw_clone);
        });
        Controller { raw: self_raw }
    }

    /// Adds a new listener and spins up a new thread to check it.
    ///
    /// The added listener can never be removed, due to the fact that the TcpListener lacks a shutdown method.
    ///
    /// # Errors
    /// * A call to `listener.try_clone()` failed for some reason.
    pub fn add_listener(&mut self, listener: TcpListener) -> Result<(), io::Error> {
        let listener_clone = try!(listener.try_clone());
        let tx_clone = self.raw.tx.lock().unwrap().clone();
        thread::spawn(|| {
            check_listener(listener_clone, tx_clone);
        });
        Ok(())
    }
}

/// Raw representation of a controller. Used internally for things.
#[derive(Debug)]
pub struct ControllerRaw {
    pub connections: RwLock<Vec<Connection>>,
    pub tx: Mutex<Sender<ControllerMessage>>,
}

#[derive(Debug)]
/// Represents a single connection without any notion of client or server.
///
/// It's own struct to allow for hooks and the like.
pub struct Connection {
    pub channel: Mutex<Sender<ConnectionMessage>>,
}

/// Sent in the case of an error that should be sent to the peer.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkError {
    /// If the versions mismatch sufficently to become incompatible with each other.
    VersionMismatch(String, String),
    /// If both peers have should_crash == false, then this error should be sent.
    ///
    /// Do note that this error should not be rewrapped into a reerror, since it would cause a loop.
    /// Instead, it should be logged and ignored, as the connection will be killed shortly after.
    ShouldCrashBothTrue,
}

impl Display for NetworkError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            NetworkError::VersionMismatch(ref ver1, ref ver2) => {
                write!(fmt,
                       "VersionMismatch: The versions of the client and server attempting to \
                        connect mismatch. ver1: {}, ver2: {}",
                       ver1,
                       ver2)
            }
            NetworkError::ShouldCrashBothTrue => {
                write!(fmt,
                       "ShouldCrashBothTrue: Both peers have should_crash == false.")
            }
        }
    }
}

impl Error for NetworkError {
    fn description(&self) -> &str {
        match *self {
            NetworkError::VersionMismatch(_, _) => {
                "VersionMismatch: The versions of the client and server attempting to connect \
                 mismatch."
            }
            NetworkError::ShouldCrashBothTrue => {
                "ShouldCrashBothTrue: Both peers have should_crash == false."
            }
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            NetworkError::VersionMismatch(_, _) => None,
            NetworkError::ShouldCrashBothTrue => None,
        }
    }
}

/// Messages that can be sent between peers to facilitate vairous actions.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkPacket {
    /// Sent on connection to verify everything is in sync.
    Init {
        /// The curent version of the local game.
        ///
        /// Should be formatted according to Scematic Versioning.
        version: String,
        /// If the local game should crash when an error occours.
        ///
        /// Two peers should not have this as false, because should_crash will send the error to the
        /// remote peer and make it crash instead.
        /// This would cause a infinite loop if both were to do it.
        should_crash: bool,
    },
    /// An error that should crash the game and show an error to the user, but only on a client.
    Error(NetworkError),
}

/// Message sent to a connection to do vairous actions.
#[derive(Debug, Clone, Copy)]
pub enum ConnectionMessage {
    DoNothing,
}

/// Channel message sent to controller to dictate certain actions.
#[derive(Debug, Clone)]
pub enum ControllerMessage {
    /// Add a socket, spinning up a new thread in the process.
    AddSocket(Sender<ConnectionMessage>, String),
}

/// Parses a str to a SocketAddr.
///
/// This is a function because while str implements ToSocketAddrs, it requires a good bit of boilerplate to use.
///
/// #Panics
/// * Calling with a localhost ip address: Use 127.0.0.1 instead.
/// * Calling with an ip address that resolves to more than 1 ip address.
pub fn ip(ip_addr: &str) -> SocketAddr {
    if ip_addr.starts_with("localhost") {
        panic!("because localhost can resolve to both 127.0.0.1, and the various IPV6 versions \
                of 127.0.0.1, it may not be used. please instead use 127.0.0.1");
    }
    let mut iter = ip_addr.to_socket_addrs().unwrap();
    let ip = iter.next().unwrap();
    if iter.next() != None {
        panic!("the given ip to net::ip() resolved to more than 1 SocketAddr");
    }
    ip
}

fn check_controller_channel(rx: Receiver<ControllerMessage>, controller: Arc<ControllerRaw>) {
    loop {
        match rx.recv() {
            Ok(msg) => {
                match msg {
                    ControllerMessage::AddSocket(tx_connection, _addr) => {
                        // TODO: Add a hook allowing intersepting the addr and denying the connection.
                        controller.connections
                                  .write()
                                  .unwrap()
                                  .push(Connection { channel: Mutex::new(tx_connection) });
                    }
                }
            }
            Err(_err) => {
                debug!("Channel connected to controller disconnected");
                break;
            }
        }
    }
}

fn check_listener(listener: TcpListener, channel_: Sender<ControllerMessage>) {
    loop {
        match listener.accept() {
            Ok((stream, addr)) => {
                let (tx, rx) = channel();
                match channel_.send(ControllerMessage::AddSocket(tx, addr.to_string())) {
                    Ok(()) => {}
                    Err(_err) => {
                        debug!("listener {:?} stopped accepting because of channel close",
                               listener);
                        break;
                    }
                }
                let stream_clone = stream.try_clone().unwrap();
                thread::spawn(|| check_stream_send(rx, stream));
                thread::spawn(move || check_stream_recv(stream_clone, addr));
            }
            Err(err) => panic!("{}", err),  // TODO: Better handle errors.
        }
    }
}

fn check_stream_send(rx: Receiver<ConnectionMessage>, _stream: TcpStream) {
    loop {
        match rx.recv().unwrap() {
            ConnectionMessage::DoNothing => {},
        }
    }
}

fn check_stream_recv(mut stream: TcpStream, addr: SocketAddr) {
    'thread: loop {
        let mut header: [u8; 6] = [0; 6];
        'read_header: loop {
            let maybe_err = (&mut stream).take(6).read_exact(&mut header);
            if let Err(err) = maybe_err {
                match err.kind() {
                    io::ErrorKind::ConnectionReset | io::ErrorKind::ConnectionAborted => {
                        info!("Connection with ip {} reset or aborted.", addr);
                        break 'thread;
                    }
                    io::ErrorKind::Interrupted => continue 'read_header,
                    _ => {
                        panic!("error not accounted for occoured on socket with address {}. \
                                display: {}",
                               addr,
                               err)
                    }
                }
            }
            break;
        }
        let len = get_packet_length(header).unwrap();
        let mut bytes: Vec<u8> = Vec::new();
        'read_data: loop {
            let maybe_error = (&mut stream).take(len as u64).read_to_end(&mut bytes);
            if let Err(err) = maybe_error {
                match err.kind() {
                    io::ErrorKind::ConnectionReset | io::ErrorKind::ConnectionAborted => {
                        info!("Connection with ip {} reset or aborted.", addr);
                        break 'thread;
                    }
                    io::ErrorKind::Interrupted => continue 'read_data,
                    _ => {
                        panic!("error not accounted for occoured on socket with address {}. \
                                display: {}",
                               addr,
                               err)
                    }
                }
            }
            break;
        }
        let message = deserialize_packet(&bytes).unwrap();
        handle_message(message);
    }
}

fn deserialize_packet(to_de: &[u8]) -> Result<NetworkPacket, DeserializeError> {
    deserialize(to_de)
}

/// Returns the length of a given packet, or a None if the first four bytes do not match NET_MAGIC_NUMBER.
fn get_packet_length(to_ln: [u8; 6]) -> Option<u16> {
    let (first_four, next_two) = to_ln.split_at(4);
    let should_be_magic_num = LittleEndian::read_u32(&first_four);
    if should_be_magic_num != NET_MAGIC_NUMBER {
        return None;
    }
    let length = LittleEndian::read_u16(&next_two);
    Some(length)
}

fn handle_message(_message: NetworkPacket) {
    unimplemented!()
}

#[allow(unused)]
fn seralize_packet(to_ser: &NetworkPacket) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::new();
    result.write_u32::<LittleEndian>(NET_MAGIC_NUMBER).unwrap();   // No possible errors here.
    // The NET_MAGIC_NUMBER is used before every packet, so incase the stream is desynced for whatever reason, the game doesn't just read arbratrary data and crash badly.
    // Instead, it can either recover somehow, by disconnecting and reconnecting, or just erroring gracefully.
    let mut encoded = serialize(to_ser, SizeLimit::Infinite).unwrap();
    // Since the size limit is infinite and i'm not encoding to a stream, there is no error and I can safely unwrap();
    result.write_u16::<LittleEndian>(encoded.len() as u16).unwrap();
    result.append(&mut encoded);
    result
}
<|endoftext|>


<commit_before>extern crate nom;

use std::str;
use nom::{
    is_hex_digit,
    digit,
    alpha,
    alphanumeric,
};

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

fn is_anon(c: char) -> bool {
    c == '[' || c == ']' || is_ws(c)
}

#[derive(PartialEq, Debug)]
pub struct Langtag<'a> {
    language: &'a str,
    subtags:  Vec<&'a str>,
}
/* [144s] LANGTAG */
named!(pub langtag<&str, Langtag>, do_parse!(
    tag!("@") >>
    language: alpha >>
    tag!("-") >>
    subtags:  separated_list_complete!(
        tag!("-"),
        alphanumeric
    ) >>
    (Langtag{
        language: language,
        subtags:  subtags,
    })
));

#[derive(PartialEq, Debug)]
pub struct Integer<'a> {
    sign:          Option<&'a str>,
    integer_part:  &'a str,
}
/* [19] INTEGER */
named!(pub integer<&str, Integer>, do_parse!(
    sign:         opt!(alt!(tag!("+") | tag!("-"))) >>
    integer_part: digit                             >>
    (Integer{
        sign:          sign,
        integer_part:  integer_part,
    })
));

#[derive(PartialEq, Debug)]
pub struct Decimal<'a> {
    sign:          Option<&'a str>,
    integer_part:  Option<&'a str>,
    decimal_point: &'a str,
    decimal_part:  &'a str,
}
/* [20] DECIMAL */
named!(pub decimal<&str, Decimal>, do_parse!(
    sign:          opt!(alt!(tag!("+") | tag!("-"))) >>
    integer_part:  opt!(digit)                       >>
    decimal_point: tag!(".")                         >>
    decimal_part:  digit                             >>
    (Decimal{
        sign:          sign,
        integer_part:  integer_part,
        decimal_point: decimal_point,
        decimal_part:  decimal_part,
    })
));

#[derive(PartialEq, Debug)]
pub enum Mantissa<'a> {
    IntegerDecimal {
        integer_part:  &'a str,
        decimal_point: &'a str,
        decimal_part:  Option<&'a str>,
    },
    Decimal {
        decimal_point: &'a str,
        decimal_part:  &'a str,
    },
    Integer {
        integer_part: &'a str,
    },
}
#[derive(PartialEq, Debug)]
pub struct Double<'a> {
    sign:     Option<&'a str>,
    mantissa: Mantissa<'a>,
    exponent: Exponent<'a>,
}
/* [21] DOUBLE */
named!(pub double<&str, Double>, do_parse!(
    sign:     opt!(alt!(tag!("+") | tag!("-"))) >>
    mantissa: alt!(
        do_parse!(
            integer_part:  digit       >>
            decimal_point: tag!(".")   >>
            decimal_part:  opt!(digit) >>
            (Mantissa::IntegerDecimal{
                integer_part:  integer_part,
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            decimal_point: tag!(".") >>
            decimal_part:  digit     >>
            (Mantissa::Decimal{
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            integer_part: digit >>
            (Mantissa::Integer{
                integer_part: integer_part,
            })
        )
    ) >>
    exponent: exponent >>
    (Double{
        sign:     sign,
        mantissa: mantissa,
        exponent: exponent,
    })
));

#[derive(PartialEq, Debug)]
pub struct Exponent<'a> {
    exponent_symbol: &'a str,
    sign:            Option<&'a str>,
    exponent_number: &'a str,
}

/* [154s] EXPONENT */
named!(pub exponent<&str, Exponent>, do_parse!(
    exponent_symbol: alt!(tag!("e") | tag!("E"))       >>
    sign:            opt!(alt!(tag!("+") | tag!("-"))) >>
    exponent_number: digit                             >>
    (Exponent{
        exponent_symbol: exponent_symbol,
        sign:            sign,
        exponent_number: exponent_number,
    })
));

/* [161s] WS */
named!(pub ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(pub anon<&str, &str>, verify!(
    take_while_s!(is_anon),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '['
            } else if idx == len - 1 {
                c == ']'
            } else {
                is_ws(c)
            }
        })
    }
));

/* [170s] PERCENT */
named!(pub percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

#[cfg(test)]
mod test {
    use super::*;
    use nom::IResult;
    use nom::ErrorKind;

    #[test]
    fn langtag_normal_test() {
        let input    = "@en-a-bbb-a-ccc,rest";
        let expected = IResult::Done(",rest", Langtag{
            language: "en",
            subtags:  vec!["a", "bbb", "a", "ccc"]
        });
        assert_eq!(langtag(input), expected);
    }

    #[test]
    fn langtag_abnormal_test() {
        let input    = "@en01-a-bbb-a-ccc,rest";
        let expected = IResult::Error(ErrorKind::Tag);
        assert_eq!(langtag(input), expected);
    }

    #[test]
    fn integer_normal_test() {
        let input    = "-1234rest";
        let expected = IResult::Done("rest", Integer{
            sign:          Some("-"),
            integer_part:  "1234",
        });
        assert_eq!(integer(input), expected);
    }

    #[test]
    fn decimal_normal_test() {
        let input    = "-1234.5678rest";
        let expected = IResult::Done("rest", Decimal{
            sign:          Some("-"),
            integer_part:  Some("1234"),
            decimal_point: ".",
            decimal_part:  "5678",
        });
        assert_eq!(decimal(input), expected);
    }

    #[test]
    fn double_normal_test() {
        let input    = "-1234.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::IntegerDecimal {
                integer_part:  "1234",
                decimal_point: ".",
                decimal_part:  Some("5678"),
            },
            exponent: exponent("e-0123456789").unwrap().1,
        });
        assert_eq!(double(input), expected);

        let input    = "-.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::Decimal {
                decimal_point: ".",
                decimal_part:  "5678",
            },
            exponent: exponent("e-0123456789").unwrap().1,
        });
        assert_eq!(double(input), expected);

        let input    = "+5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("+"),
            mantissa: Mantissa::Integer {
                integer_part: "5678",
            },
            exponent: exponent("e-0123456789").unwrap().1,
        });
        assert_eq!(double(input), expected);
    }

    #[test]
    fn exponent_normal_test() {
        let input    = "e-0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            Some("-"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "E+0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "E",
            sign:            Some("+"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "e0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            None,
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);
    }

    #[test]
    fn ws_test() {
        assert_eq!(ws(" 	\r\nrest"), IResult::Done("rest", " 	\r\n"));
    }

    #[test]
    fn anon_test() {
        assert_eq!(anon("[ ]a"), IResult::Done("a", "[ ]"));
    }

    #[test]
    fn percent_test() {
        assert_eq!(percent("%2Abc"), IResult::Done("bc", "%2A"));
    }
}
<commit_msg>Fix terminal::primitive tests<commit_after>extern crate nom;

use std::str;
use nom::{
    is_hex_digit,
    digit,
    alpha,
    alphanumeric,
};

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

#[derive(PartialEq, Debug)]
pub struct Langtag<'a> {
    language: &'a str,
    subtags:  Vec<&'a str>,
}
/* [144s] LANGTAG */
named!(pub langtag<&str, Langtag>, do_parse!(
    tag!("@") >>
    language: alpha >>
    tag!("-") >>
    subtags:  separated_list_complete!(
        tag!("-"),
        alphanumeric
    ) >>
    (Langtag{
        language: language,
        subtags:  subtags,
    })
));

#[derive(PartialEq, Debug)]
pub struct Integer<'a> {
    sign:          Option<&'a str>,
    integer_part:  &'a str,
}
/* [19] INTEGER */
named!(pub integer<&str, Integer>, do_parse!(
    sign:         opt!(alt!(tag!("+") | tag!("-"))) >>
    integer_part: digit                             >>
    (Integer{
        sign:          sign,
        integer_part:  integer_part,
    })
));

#[derive(PartialEq, Debug)]
pub struct Decimal<'a> {
    sign:          Option<&'a str>,
    integer_part:  Option<&'a str>,
    decimal_point: &'a str,
    decimal_part:  &'a str,
}
/* [20] DECIMAL */
named!(pub decimal<&str, Decimal>, do_parse!(
    sign:          opt!(alt!(tag!("+") | tag!("-"))) >>
    integer_part:  opt!(digit)                       >>
    decimal_point: tag!(".")                         >>
    decimal_part:  digit                             >>
    (Decimal{
        sign:          sign,
        integer_part:  integer_part,
        decimal_point: decimal_point,
        decimal_part:  decimal_part,
    })
));

#[derive(PartialEq, Debug)]
pub enum Mantissa<'a> {
    IntegerDecimal {
        integer_part:  &'a str,
        decimal_point: &'a str,
        decimal_part:  Option<&'a str>,
    },
    Decimal {
        decimal_point: &'a str,
        decimal_part:  &'a str,
    },
    Integer {
        integer_part: &'a str,
    },
}
#[derive(PartialEq, Debug)]
pub struct Double<'a> {
    sign:     Option<&'a str>,
    mantissa: Mantissa<'a>,
    exponent: Exponent<'a>,
}
/* [21] DOUBLE */
named!(pub double<&str, Double>, do_parse!(
    sign:     opt!(alt!(tag!("+") | tag!("-"))) >>
    mantissa: alt!(
        do_parse!(
            integer_part:  digit       >>
            decimal_point: tag!(".")   >>
            decimal_part:  opt!(digit) >>
            (Mantissa::IntegerDecimal{
                integer_part:  integer_part,
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            decimal_point: tag!(".") >>
            decimal_part:  digit     >>
            (Mantissa::Decimal{
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            integer_part: digit >>
            (Mantissa::Integer{
                integer_part: integer_part,
            })
        )
    ) >>
    exponent: exponent >>
    (Double{
        sign:     sign,
        mantissa: mantissa,
        exponent: exponent,
    })
));

#[derive(PartialEq, Debug)]
pub struct Exponent<'a> {
    exponent_symbol: &'a str,
    sign:            Option<&'a str>,
    exponent_number: &'a str,
}

/* [154s] EXPONENT */
named!(pub exponent<&str, Exponent>, do_parse!(
    exponent_symbol: alt!(tag!("e") | tag!("E"))       >>
    sign:            opt!(alt!(tag!("+") | tag!("-"))) >>
    exponent_number: digit                             >>
    (Exponent{
        exponent_symbol: exponent_symbol,
        sign:            sign,
        exponent_number: exponent_number,
    })
));

/* [161s] WS */
named!(pub ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(pub anon<&str, &str>, delimited!(
    tag!("["),
    take_while_s!(is_ws),
    tag!("]")
));

/* [170s] PERCENT */
named!(pub percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

#[cfg(test)]
mod test {
    use super::*;
    use nom::IResult;
    use nom::ErrorKind;

    #[test]
    fn langtag_normal_test() {
        let input    = "@en-a-bbb-a-ccc,rest";
        let expected = IResult::Done(",rest", Langtag{
            language: "en",
            subtags:  vec!["a", "bbb", "a", "ccc"]
        });
        assert_eq!(langtag(input), expected);
    }

    #[test]
    fn langtag_abnormal_test() {
        let input    = "@en01-a-bbb-a-ccc,rest";
        let expected = IResult::Error(ErrorKind::Tag);
        assert_eq!(langtag(input), expected);
    }

    #[test]
    fn integer_normal_test() {
        let input    = "-1234rest";
        let expected = IResult::Done("rest", Integer{
            sign:          Some("-"),
            integer_part:  "1234",
        });
        assert_eq!(integer(input), expected);
    }

    #[test]
    fn decimal_normal_test() {
        let input    = "-1234.5678rest";
        let expected = IResult::Done("rest", Decimal{
            sign:          Some("-"),
            integer_part:  Some("1234"),
            decimal_point: ".",
            decimal_part:  "5678",
        });
        assert_eq!(decimal(input), expected);
    }

    #[test]
    fn double_normal_test() {
        let input    = "-1234.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::IntegerDecimal {
                integer_part:  "1234",
                decimal_point: ".",
                decimal_part:  Some("5678"),
            },
            exponent: exponent("e-0123456789").unwrap().1,
        });
        assert_eq!(double(input), expected);

        let input    = "-.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::Decimal {
                decimal_point: ".",
                decimal_part:  "5678",
            },
            exponent: exponent("e-0123456789").unwrap().1,
        });
        assert_eq!(double(input), expected);

        let input    = "+5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("+"),
            mantissa: Mantissa::Integer {
                integer_part: "5678",
            },
            exponent: exponent("e-0123456789").unwrap().1,
        });
        assert_eq!(double(input), expected);
    }

    #[test]
    fn exponent_normal_test() {
        let input    = "e-0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            Some("-"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "E+0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "E",
            sign:            Some("+"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "e0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            None,
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);
    }

    #[test]
    fn ws_test() {
        let input    = " 	\r\nrest";
        let expected = IResult::Done("rest", " 	\r\n");
        assert_eq!(ws(input), expected);
    }

    #[test]
    fn anon_test() {
        let input    = "[ 	\r\n]rest";
        let expected = IResult::Done("rest", " 	\r\n");
        assert_eq!(anon(input), expected);
    }

    #[test]
    fn percent_test() {
        let input    = "%2Arest";
        let expected = IResult::Done("rest", "%2A");
        assert_eq!(percent(input), expected);
    }
}
<|endoftext|>


<commit_before>// run-pass

#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![feature(never_type)]

use std::mem::size_of;
use std::num::NonZeroU8;

struct t {a: u8, b: i8}
struct u {a: u8, b: i8, c: u8}
struct v {a: u8, b: i8, c: v2, d: u32}
struct v2 {u: char, v: u8}
struct w {a: isize, b: ()}
struct x {a: isize, b: (), c: ()}
struct y {x: isize}

enum e1 {
    a(u8, u32), b(u32), c
}
enum e2 {
    a(u32), b
}

#[repr(C, u8)]
enum e3 {
    a([u16; 0], u8), b
}

struct ReorderedStruct {
    a: u8,
    b: u16,
    c: u8
}

enum ReorderedEnum {
    A(u8, u16, u8),
    B(u8, u16, u8),
}

enum ReorderedEnum2 {
    A(u8, u32, u8),
    B(u16, u8, u16, u8),

    // 0x100 niche variants.
    _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
    _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
    _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
    _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
    _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
    _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
    _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
    _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
    _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
    _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
    _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
    _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
    _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
    _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
    _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
    _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
}

enum EnumEmpty {}

enum EnumSingle1 {
    A,
}

enum EnumSingle2 {
    A = 42 as isize,
}

enum EnumSingle3 {
    A,
    B(!),
}

#[repr(u8)]
enum EnumSingle4 {
    A,
}

#[repr(u8)]
enum EnumSingle5 {
    A = 42 as u8,
}

enum EnumWithMaybeUninhabitedVariant<T> {
    A(&'static ()),
    B(&'static (), T),
    C,
}

enum NicheFilledEnumWithAbsentVariant {
    A(&'static ()),
    B((), !),
    C,
}

enum Option2<A, B> {
    Some(A, B),
    None
}

pub enum CanBeNicheFilledButShouldnt {
    A(NonZeroU8, u32),
    B
}
pub enum AlwaysTagged {
    A(u8, u32),
    B
}

pub fn main() {
    assert_eq!(size_of::<u8>(), 1 as usize);
    assert_eq!(size_of::<u32>(), 4 as usize);
    assert_eq!(size_of::<char>(), 4 as usize);
    assert_eq!(size_of::<i8>(), 1 as usize);
    assert_eq!(size_of::<i32>(), 4 as usize);
    assert_eq!(size_of::<t>(), 2 as usize);
    assert_eq!(size_of::<u>(), 3 as usize);
    // Alignment causes padding before the char and the u32.

    assert_eq!(size_of::<v>(),
                16 as usize);
    assert_eq!(size_of::<isize>(), size_of::<usize>());
    assert_eq!(size_of::<w>(), size_of::<isize>());
    assert_eq!(size_of::<x>(), size_of::<isize>());
    assert_eq!(size_of::<isize>(), size_of::<y>());

    // Make sure enum types are the appropriate size, mostly
    // around ensuring alignment is handled properly

    assert_eq!(size_of::<e1>(), 8 as usize);
    assert_eq!(size_of::<e2>(), 8 as usize);
    assert_eq!(size_of::<e3>(), 4 as usize);
    assert_eq!(size_of::<ReorderedStruct>(), 4);
    assert_eq!(size_of::<ReorderedEnum>(), 6);
    assert_eq!(size_of::<ReorderedEnum2>(), 8);

    assert_eq!(size_of::<EnumEmpty>(), 0);
    assert_eq!(size_of::<EnumSingle1>(), 0);
    assert_eq!(size_of::<EnumSingle2>(), 0);
    assert_eq!(size_of::<EnumSingle3>(), 0);
    assert_eq!(size_of::<EnumSingle4>(), 1);
    assert_eq!(size_of::<EnumSingle5>(), 1);

    assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
               size_of::<EnumWithMaybeUninhabitedVariant<()>>());
    assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());

    assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
    assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
    assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
    assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());

    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
    assert_eq!(size_of::<AlwaysTagged>(), 8);
    assert_eq!(size_of::<Option<AlwaysTagged>>(), 8);
    assert_eq!(size_of::<Option<Option<AlwaysTagged>>>(), 8);
}
<commit_msg>document test changes<commit_after>// run-pass

#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![feature(never_type)]

use std::mem::size_of;
use std::num::NonZeroU8;

struct t {a: u8, b: i8}
struct u {a: u8, b: i8, c: u8}
struct v {a: u8, b: i8, c: v2, d: u32}
struct v2 {u: char, v: u8}
struct w {a: isize, b: ()}
struct x {a: isize, b: (), c: ()}
struct y {x: isize}

enum e1 {
    a(u8, u32), b(u32), c
}
enum e2 {
    a(u32), b
}

#[repr(C, u8)]
enum e3 {
    a([u16; 0], u8), b
}

struct ReorderedStruct {
    a: u8,
    b: u16,
    c: u8
}

enum ReorderedEnum {
    A(u8, u16, u8),
    B(u8, u16, u8),
}

enum ReorderedEnum2 {
    A(u8, u32, u8),
    B(u16, u8, u16, u8),

    // 0x100 niche variants.
    _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
    _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
    _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
    _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
    _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
    _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
    _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
    _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
    _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
    _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
    _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
    _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
    _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
    _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
    _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
    _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
}

enum EnumEmpty {}

enum EnumSingle1 {
    A,
}

enum EnumSingle2 {
    A = 42 as isize,
}

enum EnumSingle3 {
    A,
    B(!),
}

#[repr(u8)]
enum EnumSingle4 {
    A,
}

#[repr(u8)]
enum EnumSingle5 {
    A = 42 as u8,
}

enum EnumWithMaybeUninhabitedVariant<T> {
    A(&'static ()),
    B(&'static (), T),
    C,
}

enum NicheFilledEnumWithAbsentVariant {
    A(&'static ()),
    B((), !),
    C,
}

enum Option2<A, B> {
    Some(A, B),
    None
}

// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
//   Niche-filling:
//     { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
//   Tagged:
//     { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
// Both are the same size (due to padding),
// but the tagged layout is better as the tag creates a niche with 254 invalid values,
// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
pub enum CanBeNicheFilledButShouldnt {
    A(NonZeroU8, u32),
    B
}
pub enum AlwaysTaggedBecauseItHasNoNiche {
    A(u8, u32),
    B
}

pub fn main() {
    assert_eq!(size_of::<u8>(), 1 as usize);
    assert_eq!(size_of::<u32>(), 4 as usize);
    assert_eq!(size_of::<char>(), 4 as usize);
    assert_eq!(size_of::<i8>(), 1 as usize);
    assert_eq!(size_of::<i32>(), 4 as usize);
    assert_eq!(size_of::<t>(), 2 as usize);
    assert_eq!(size_of::<u>(), 3 as usize);
    // Alignment causes padding before the char and the u32.

    assert_eq!(size_of::<v>(),
                16 as usize);
    assert_eq!(size_of::<isize>(), size_of::<usize>());
    assert_eq!(size_of::<w>(), size_of::<isize>());
    assert_eq!(size_of::<x>(), size_of::<isize>());
    assert_eq!(size_of::<isize>(), size_of::<y>());

    // Make sure enum types are the appropriate size, mostly
    // around ensuring alignment is handled properly

    assert_eq!(size_of::<e1>(), 8 as usize);
    assert_eq!(size_of::<e2>(), 8 as usize);
    assert_eq!(size_of::<e3>(), 4 as usize);
    assert_eq!(size_of::<ReorderedStruct>(), 4);
    assert_eq!(size_of::<ReorderedEnum>(), 6);
    assert_eq!(size_of::<ReorderedEnum2>(), 8);

    assert_eq!(size_of::<EnumEmpty>(), 0);
    assert_eq!(size_of::<EnumSingle1>(), 0);
    assert_eq!(size_of::<EnumSingle2>(), 0);
    assert_eq!(size_of::<EnumSingle3>(), 0);
    assert_eq!(size_of::<EnumSingle4>(), 1);
    assert_eq!(size_of::<EnumSingle5>(), 1);

    assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
               size_of::<EnumWithMaybeUninhabitedVariant<()>>());
    assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());

    assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
    assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
    assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
    assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());

    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
    assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
    assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
    assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
}
<|endoftext|>