<commit_before>use std::collections::HashMap;
use std::fmt;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Metadata {
  /// Marks whether the current metadata block is the last.
  is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  length: u32,
  /// Block data containing one of the eight different types of metadata.
  pub data: Data,
}

/// An enum that represents a metadata block type.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
  /// Represents the current block is stream information.
  StreamInfo,
  /// Represents the current block is padding.
  Padding,
  /// Represents the current block is application data.
  Application,
  /// Represents the current block is a seek table.
  SeekTable,
  /// Represents the current block is a vorbis comment.
  VorbisComment,
  /// Represents the current block is a cue sheet.
  CueSheet,
  /// Represents the current block is a picture.
  Picture,
  /// Represents the current block is unknow.
  Unknown,
}

macro_rules! is_block_type (
  ($(
     $(#[$attr: meta])* ($name: ident) -> $block_type: ident
   )+) => (
    $(
    $(#[$attr])*
    #[inline]
    pub fn $name(&self) -> bool {
      self.data_type() == Type::$block_type
    }
    )+
  );
);

impl Metadata {
  /// Constructs a new `Metadata` struct based on the arguments passed in.
  pub fn new(is_last: bool, length: u32, data: Data) -> Self {
    Metadata {
      is_last: is_last,
      length: length,
      data: data,
    }
  }

  /// Returns whether the current metadata block is the last.
  #[inline]
  pub fn is_last(&self) -> bool {
    self.is_last
  }

  /// Returns the metadata block's type.
  pub fn data_type(&self) -> Type {
    match self.data {
      Data::StreamInfo(_)    => Type::StreamInfo,
      Data::Padding(_)       => Type::Padding,
      Data::Application(_)   => Type::Application,
      Data::SeekTable(_)     => Type::SeekTable,
      Data::VorbisComment(_) => Type::VorbisComment,
      Data::CueSheet(_)      => Type::CueSheet,
      Data::Picture(_)       => Type::Picture,
      Data::Unknown(_)       => Type::Unknown,
    }
  }

  is_block_type! {
    /// Returns true when the current `Metadata` is `StreamInfo`.
    (is_stream_info) -> StreamInfo
    /// Returns true when the current `Metadata` is `Padding`.
    (is_padding) -> Padding
    /// Returns true when the current `Metadata` is `Application`.
    (is_application) -> Application
    /// Returns true when the current `Metadata` is `SeekTable`.
    (is_seek_table) -> SeekTable
    /// Returns true when the current `Metadata` is `VorbisComment`.
    (is_vorbis_comment) -> VorbisComment
    /// Returns true when the current `Metadata` is `CueSheet`.
    (is_cue_sheet) -> CueSheet
    /// Returns true when the current `Metadata` is `Picture`.
    (is_picture) -> Picture
    /// Returns true when the current `Metadata` is `Unknown`.
    (is_unknown) -> Unknown
  }
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  /// Constructs a zeroed out `StreamInfo` struct.
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }

  /// Returns true if `min_block_size` and `max_block_size` are different,
  /// otherwise false.
  #[inline]
  pub fn is_varied_block_size(&self) -> bool {
    self.min_block_size != self.max_block_size
  }

  /// Returns true if `min_block_size` and `max_block_size` are equal,
  /// otherwise false.
  #[inline]
  pub fn is_fixed_block_size(&self) -> bool {
    self.min_block_size == self.max_block_size
  }

  pub fn to_bytes(&self) -> Vec<u8> {
    let mut bytes = [0; 34];

    bytes[0] = (self.min_block_size >> 8) as u8;
    bytes[1] = self.min_block_size as u8;

    bytes[2] = (self.max_block_size >> 8) as u8;
    bytes[3] = self.max_block_size as u8;

    bytes[4] = (self.min_frame_size >> 16) as u8;
    bytes[5] = (self.min_frame_size >> 8) as u8;
    bytes[6] = self.min_frame_size as u8;

    bytes[7] = (self.max_frame_size >> 16) as u8;
    bytes[8] = (self.max_frame_size >> 8) as u8;
    bytes[9] = self.max_frame_size as u8;

    bytes[10] = (self.sample_rate >> 12) as u8;
    bytes[11] = (self.sample_rate >> 4) as u8;
    bytes[12] = (self.sample_rate << 4) as u8;

    bytes[12] += (self.channels - 1) << 1;
    bytes[12] += (self.bits_per_sample - 1) >> 4;
    bytes[13]  = (self.bits_per_sample - 1) << 4;

    bytes.to_vec()
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformance,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

impl fmt::Display for PictureType {
  fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
    write!(formatter, "{}", match *self {
      PictureType::Other              => "Other",
      PictureType::FileIconStandard   => "File Icon (standard)",
      PictureType::FileIcon           => "File Icon",
      PictureType::FrontCover         => "Cover (front)",
      PictureType::BackCover          => "Cover (back)",
      PictureType::LeafletPage        => "Leaflet Page",
      PictureType::Media              => "Media",
      PictureType::LeadArtist         => "Lead Artist",
      PictureType::Artist             => "Arist",
      PictureType::Conductor          => "Conductor",
      PictureType::Band               => "Band",
      PictureType::Composer           => "Composer",
      PictureType::Lyricist           => "Lyricist",
      PictureType::RecordingLocation  => "Recoding Location",
      PictureType::DuringRecording    => "During Recording",
      PictureType::DuringPerformance  => "During Performance",
      PictureType::VideoScreenCapture => "Video Screen Capture",
      PictureType::Fish               => "Fish",
      PictureType::Illustration       => "Illustration",
      PictureType::BandLogo           => "Band Logo",
      PictureType::PublisherLogo      => "Publisher Logo",
    })
  }
}

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

  #[test]
  fn test_is_varied_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 1024;

    assert!(info.is_varied_block_size());

    info.min_block_size = 2048;
    info.max_block_size = 2048;

    assert!(!info.is_varied_block_size());
  }

  #[test]
  fn test_is_fixed_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 512;

    assert!(info.is_fixed_block_size());

    info.min_block_size = 1024;
    info.max_block_size = 2048;

    assert!(!info.is_fixed_block_size());
  }
}
<commit_msg>Convert total_samples to bytes<commit_after>use std::collections::HashMap;
use std::fmt;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Metadata {
  /// Marks whether the current metadata block is the last.
  is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  length: u32,
  /// Block data containing one of the eight different types of metadata.
  pub data: Data,
}

/// An enum that represents a metadata block type.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Type {
  /// Represents the current block is stream information.
  StreamInfo,
  /// Represents the current block is padding.
  Padding,
  /// Represents the current block is application data.
  Application,
  /// Represents the current block is a seek table.
  SeekTable,
  /// Represents the current block is a vorbis comment.
  VorbisComment,
  /// Represents the current block is a cue sheet.
  CueSheet,
  /// Represents the current block is a picture.
  Picture,
  /// Represents the current block is unknow.
  Unknown,
}

macro_rules! is_block_type (
  ($(
     $(#[$attr: meta])* ($name: ident) -> $block_type: ident
   )+) => (
    $(
    $(#[$attr])*
    #[inline]
    pub fn $name(&self) -> bool {
      self.data_type() == Type::$block_type
    }
    )+
  );
);

impl Metadata {
  /// Constructs a new `Metadata` struct based on the arguments passed in.
  pub fn new(is_last: bool, length: u32, data: Data) -> Self {
    Metadata {
      is_last: is_last,
      length: length,
      data: data,
    }
  }

  /// Returns whether the current metadata block is the last.
  #[inline]
  pub fn is_last(&self) -> bool {
    self.is_last
  }

  /// Returns the metadata block's type.
  pub fn data_type(&self) -> Type {
    match self.data {
      Data::StreamInfo(_)    => Type::StreamInfo,
      Data::Padding(_)       => Type::Padding,
      Data::Application(_)   => Type::Application,
      Data::SeekTable(_)     => Type::SeekTable,
      Data::VorbisComment(_) => Type::VorbisComment,
      Data::CueSheet(_)      => Type::CueSheet,
      Data::Picture(_)       => Type::Picture,
      Data::Unknown(_)       => Type::Unknown,
    }
  }

  is_block_type! {
    /// Returns true when the current `Metadata` is `StreamInfo`.
    (is_stream_info) -> StreamInfo
    /// Returns true when the current `Metadata` is `Padding`.
    (is_padding) -> Padding
    /// Returns true when the current `Metadata` is `Application`.
    (is_application) -> Application
    /// Returns true when the current `Metadata` is `SeekTable`.
    (is_seek_table) -> SeekTable
    /// Returns true when the current `Metadata` is `VorbisComment`.
    (is_vorbis_comment) -> VorbisComment
    /// Returns true when the current `Metadata` is `CueSheet`.
    (is_cue_sheet) -> CueSheet
    /// Returns true when the current `Metadata` is `Picture`.
    (is_picture) -> Picture
    /// Returns true when the current `Metadata` is `Unknown`.
    (is_unknown) -> Unknown
  }
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  /// Constructs a zeroed out `StreamInfo` struct.
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }

  /// Returns true if `min_block_size` and `max_block_size` are different,
  /// otherwise false.
  #[inline]
  pub fn is_varied_block_size(&self) -> bool {
    self.min_block_size != self.max_block_size
  }

  /// Returns true if `min_block_size` and `max_block_size` are equal,
  /// otherwise false.
  #[inline]
  pub fn is_fixed_block_size(&self) -> bool {
    self.min_block_size == self.max_block_size
  }

  pub fn to_bytes(&self) -> Vec<u8> {
    let mut bytes = [0; 34];

    bytes[0] = (self.min_block_size >> 8) as u8;
    bytes[1] = self.min_block_size as u8;

    bytes[2] = (self.max_block_size >> 8) as u8;
    bytes[3] = self.max_block_size as u8;

    bytes[4] = (self.min_frame_size >> 16) as u8;
    bytes[5] = (self.min_frame_size >> 8) as u8;
    bytes[6] = self.min_frame_size as u8;

    bytes[7] = (self.max_frame_size >> 16) as u8;
    bytes[8] = (self.max_frame_size >> 8) as u8;
    bytes[9] = self.max_frame_size as u8;

    bytes[10] = (self.sample_rate >> 12) as u8;
    bytes[11] = (self.sample_rate >> 4) as u8;
    bytes[12] = (self.sample_rate << 4) as u8;

    bytes[12] += (self.channels - 1) << 1;
    bytes[12] += (self.bits_per_sample - 1) >> 4;
    bytes[13]  = (self.bits_per_sample - 1) << 4;

    bytes[13] += (self.total_samples >> 32) as u8;
    bytes[14]  = (self.total_samples >> 24) as u8;
    bytes[15]  = (self.total_samples >> 16) as u8;
    bytes[16]  = (self.total_samples >> 8) as u8;
    bytes[17]  = self.total_samples as u8;

    bytes.to_vec()
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformance,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

impl fmt::Display for PictureType {
  fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
    write!(formatter, "{}", match *self {
      PictureType::Other              => "Other",
      PictureType::FileIconStandard   => "File Icon (standard)",
      PictureType::FileIcon           => "File Icon",
      PictureType::FrontCover         => "Cover (front)",
      PictureType::BackCover          => "Cover (back)",
      PictureType::LeafletPage        => "Leaflet Page",
      PictureType::Media              => "Media",
      PictureType::LeadArtist         => "Lead Artist",
      PictureType::Artist             => "Arist",
      PictureType::Conductor          => "Conductor",
      PictureType::Band               => "Band",
      PictureType::Composer           => "Composer",
      PictureType::Lyricist           => "Lyricist",
      PictureType::RecordingLocation  => "Recoding Location",
      PictureType::DuringRecording    => "During Recording",
      PictureType::DuringPerformance  => "During Performance",
      PictureType::VideoScreenCapture => "Video Screen Capture",
      PictureType::Fish               => "Fish",
      PictureType::Illustration       => "Illustration",
      PictureType::BandLogo           => "Band Logo",
      PictureType::PublisherLogo      => "Publisher Logo",
    })
  }
}

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

  #[test]
  fn test_is_varied_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 1024;

    assert!(info.is_varied_block_size());

    info.min_block_size = 2048;
    info.max_block_size = 2048;

    assert!(!info.is_varied_block_size());
  }

  #[test]
  fn test_is_fixed_block_size() {
    let mut info = StreamInfo::new();

    info.min_block_size = 512;
    info.max_block_size = 512;

    assert!(info.is_fixed_block_size());

    info.min_block_size = 1024;
    info.max_block_size = 2048;

    assert!(!info.is_fixed_block_size());
  }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use protobuf::descriptor::*;

use crate::customize::ctx::CustomizeElemCtx;
use crate::customize::rustproto_proto::customize_from_rustproto_for_enum;
use crate::gen::code_writer::*;
use crate::gen::file_index::FileIndex;
use crate::gen::inside::protobuf_crate_path;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum_value;
use crate::gen::rust::EXPR_NONE;
use crate::gen::rust_name::RustIdent;
use crate::gen::rust_name::RustIdentWithPath;
use crate::gen::scope::EnumValueWithContext;
use crate::gen::scope::EnumWithScope;
use crate::gen::scope::RootScope;
use crate::gen::scope::WithScope;

#[derive(Clone)]
pub(crate) struct EnumValueGen<'a> {
    value: EnumValueWithContext<'a>,
    enum_rust_name: RustIdentWithPath,
}

impl<'a> EnumValueGen<'a> {
    fn parse(
        value: EnumValueWithContext<'a>,
        enum_rust_name: &RustIdentWithPath,
    ) -> EnumValueGen<'a> {
        EnumValueGen {
            value: value.clone(),
            enum_rust_name: enum_rust_name.clone(),
        }
    }

    // enum value
    fn number(&self) -> i32 {
        self.value.proto.proto().number()
    }

    // name of enum variant in generated rust code
    pub fn rust_name_inner(&self) -> RustIdent {
        self.value.rust_name()
    }

    pub fn rust_name_outer(&self) -> RustIdentWithPath {
        self.enum_rust_name
            .to_path()
            .with_ident(self.rust_name_inner())
    }
}

// Codegen for enum definition
pub(crate) struct EnumGen<'a> {
    enum_with_scope: &'a EnumWithScope<'a>,
    file_index: &'a FileIndex,
    type_name: RustIdentWithPath,
    lite_runtime: bool,
    customize: CustomizeElemCtx<'a>,
    path: &'a [i32],
    info: Option<&'a SourceCodeInfo>,
}

impl<'a> EnumGen<'a> {
    pub fn new(
        enum_with_scope: &'a EnumWithScope<'a>,
        file_index: &'a FileIndex,
        customize: &CustomizeElemCtx<'a>,
        _root_scope: &RootScope,
        path: &'a [i32],
        info: Option<&'a SourceCodeInfo>,
    ) -> EnumGen<'a> {
        let customize = customize.child(
            &customize_from_rustproto_for_enum(enum_with_scope.en.proto().options.get_or_default()),
            &enum_with_scope.en,
        );
        let lite_runtime = customize.for_elem.lite_runtime.unwrap_or_else(|| {
            enum_with_scope
                .scope()
                .file_descriptor()
                .options
                .get_or_default()
                .optimize_for()
                == file_options::OptimizeMode::LITE_RUNTIME
        });

        EnumGen {
            enum_with_scope,
            type_name: enum_with_scope.rust_name().to_path(),
            lite_runtime,
            customize,
            path,
            info,
            file_index,
        }
    }

    fn index_in_file(&self) -> u32 {
        self.file_index.enum_to_index[&self.enum_with_scope.protobuf_name_to_package()]
    }

    fn allow_alias(&self) -> bool {
        self.enum_with_scope
            .en
            .proto()
            .options
            .get_or_default()
            .allow_alias()
    }

    fn values_all(&self) -> Vec<EnumValueGen> {
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    fn values_unique(&self) -> Vec<EnumValueGen> {
        let mut used = HashSet::new();
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            if !used.insert(p.proto.proto().number()) {
                continue;
            }
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    pub fn write(&self, w: &mut CodeWriter) {
        self.write_enum(w);
        if self.allow_alias() {
            w.write_line("");
            self.write_impl_eq(w);
            w.write_line("");
            self.write_impl_hash(w);
        }
        w.write_line("");
        self.write_impl_enum(w);
        if !self.lite_runtime {
            w.write_line("");
            self.write_impl_enum_full(w);
        }
        w.write_line("");
        self.write_impl_default(w);
        w.write_line("");
        self.write_impl_self(w);
    }

    fn write_impl_self(&self, w: &mut CodeWriter) {
        if !self.lite_runtime {
            w.impl_self_block(&format!("{}", self.type_name), |w| {
                self.write_generated_enum_descriptor_data(w);
            });
        }
    }

    fn write_enum(&self, w: &mut CodeWriter) {
        w.all_documentation(self.info, self.path);

        let mut derive = Vec::new();
        derive.push("Clone");
        derive.push("Copy");
        if !self.allow_alias() {
            derive.push("PartialEq");
        }
        derive.push("Eq");
        derive.push("Debug");
        if !self.allow_alias() {
            derive.push("Hash");
        } else {
            w.comment("Note: you cannot use pattern matching for enums with allow_alias option");
        }
        w.derive(&derive);
        let ref type_name = self.type_name;
        write_protoc_insertion_point_for_enum(
            w,
            &self.customize.for_elem,
            &self.enum_with_scope.en,
        );
        w.expr_block(&format!("pub enum {}", type_name), |w| {
            for value in self.values_all() {
                write_protoc_insertion_point_for_enum_value(
                    w,
                    &self.customize.for_children,
                    &value.value.proto,
                );
                if self.allow_alias() {
                    w.write_line(&format!(
                        "{}, // {}",
                        value.rust_name_inner(),
                        value.number()
                    ));
                } else {
                    w.write_line(&format!(
                        "{} = {},",
                        value.rust_name_inner(),
                        value.number()
                    ));
                }
            }
        });
    }

    fn write_fn_value(&self, w: &mut CodeWriter) {
        w.def_fn("value(&self) -> i32", |w| {
            if self.allow_alias() {
                w.match_expr("*self", |w| {
                    for value in self.values_all() {
                        w.case_expr(
                            &format!("{}", value.rust_name_outer()),
                            &format!("{}", value.number()),
                        );
                    }
                });
            } else {
                w.write_line("*self as i32")
            }
        });
    }

    fn write_impl_enum(&self, w: &mut CodeWriter) {
        let ref type_name = self.type_name;
        w.impl_for_block(
            &format!("{}::Enum", protobuf_crate_path(&self.customize.for_elem)),
            &format!("{}", type_name),
            |w| {
                self.write_fn_value(w);

                w.write_line("");
                let ref type_name = self.type_name;
                w.def_fn(
                    &format!(
                        "from_i32(value: i32) -> ::std::option::Option<{}>",
                        type_name
                    ),
                    |w| {
                        w.match_expr("value", |w| {
                            let values = self.values_unique();
                            for value in values {
                                w.write_line(&format!(
                                    "{} => ::std::option::Option::Some({}),",
                                    value.number(),
                                    value.rust_name_outer()
                                ));
                            }
                            w.write_line(&format!("_ => {}", EXPR_NONE));
                        });
                    },
                );

                w.write_line("");
                w.def_fn(&format!("values() -> &'static [Self]"), |w| {
                    w.write_line(&format!("static values: &'static [{}] = &[", type_name));
                    w.indented(|w| {
                        for value in self.values_all() {
                            w.write_line(&format!("{},", value.rust_name_outer()));
                        }
                    });
                    w.write_line("];");
                    w.write_line("values");
                });
            },
        );
    }

    fn write_impl_enum_full(&self, w: &mut CodeWriter) {
        let ref type_name = self.type_name;
        w.impl_for_block(
            &format!(
                "{}::EnumFull",
                protobuf_crate_path(&self.customize.for_elem)
            ),
            &format!("{}", type_name),
            |w| {
                // TODO: write unconditionally
                if !self.lite_runtime {
                    self.write_enum_descriptor_static(w);
                }
            },
        );
    }

    fn write_enum_descriptor_static(&self, w: &mut CodeWriter) {
        let sig = format!(
            "enum_descriptor_static() -> {}::reflect::EnumDescriptor",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.def_fn(&sig, |w| {
            w.write_line(&format!(
                "{}::reflect::EnumDescriptor::new_generated_2({}(), {})",
                protobuf_crate_path(&self.customize.for_elem),
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse()
                    .append_ident("file_descriptor".into()),
                self.index_in_file(),
            ));
        });
    }

    fn write_generated_enum_descriptor_data(&self, w: &mut CodeWriter) {
        let sig = format!(
            "generated_enum_descriptor_data() -> {}::reflect::GeneratedEnumDescriptorData",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.fn_block(
            Visibility::Path(
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse(),
            ),
            &sig,
            |w| {
                w.write_line(&format!(
                    "{}::reflect::GeneratedEnumDescriptorData::new_2::<{}>(\"{}\", {})",
                    protobuf_crate_path(&self.customize.for_elem),
                    self.type_name,
                    self.enum_with_scope.name_to_package(),
                    self.index_in_file(),
                ));
            },
        );
    }

    fn write_impl_eq(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block(
            "::std::cmp::PartialEq",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("eq(&self, other: &Self) -> bool", |w| {
                    w.write_line(&format!(
                        "{}::Enum::value(self) == {}::Enum::value(other)",
                        protobuf_crate_path(&self.customize.for_elem),
                        protobuf_crate_path(&self.customize.for_elem)
                    ));
                });
            },
        );
    }

    fn write_impl_hash(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block("::std::hash::Hash", &format!("{}", self.type_name), |w| {
            w.def_fn("hash<H : ::std::hash::Hasher>(&self, state: &mut H)", |w| {
                w.write_line(&format!(
                    "state.write_i32({}::Enum::value(self))",
                    protobuf_crate_path(&self.customize.for_elem)
                ));
            });
        });
    }

    fn write_impl_default(&self, w: &mut CodeWriter) {
        let first_value = &self.enum_with_scope.values()[0];
        if first_value.proto.proto().number() != 0 {
            // This warning is emitted only for proto2
            // (because in proto3 first enum variant number is always 0).
            // `Default` implemented unconditionally to simplify certain
            // generic operations, e. g. reading a map.
            // Also, note that even in proto2 some operations fallback to
            // first enum value, e. g. `get_xxx` for unset field,
            // so this implementation is not completely unreasonable.
            w.comment("Note, `Default` is implemented although default value is not 0");
        }
        w.impl_for_block(
            "::std::default::Default",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("default() -> Self", |w| {
                    w.write_line(&format!(
                        "{}::{}",
                        &self.type_name,
                        &first_value.rust_name()
                    ))
                });
            },
        );
    }
}
<commit_msg>Code cleanup<commit_after>use std::collections::HashSet;

use protobuf::descriptor::*;

use crate::customize::ctx::CustomizeElemCtx;
use crate::customize::rustproto_proto::customize_from_rustproto_for_enum;
use crate::gen::code_writer::*;
use crate::gen::file_index::FileIndex;
use crate::gen::inside::protobuf_crate_path;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum;
use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_enum_value;
use crate::gen::rust::EXPR_NONE;
use crate::gen::rust_name::RustIdent;
use crate::gen::rust_name::RustIdentWithPath;
use crate::gen::scope::EnumValueWithContext;
use crate::gen::scope::EnumWithScope;
use crate::gen::scope::RootScope;
use crate::gen::scope::WithScope;

#[derive(Clone)]
pub(crate) struct EnumValueGen<'a> {
    value: EnumValueWithContext<'a>,
    enum_rust_name: RustIdentWithPath,
}

impl<'a> EnumValueGen<'a> {
    fn parse(
        value: EnumValueWithContext<'a>,
        enum_rust_name: &RustIdentWithPath,
    ) -> EnumValueGen<'a> {
        EnumValueGen {
            value: value.clone(),
            enum_rust_name: enum_rust_name.clone(),
        }
    }

    // enum value
    fn number(&self) -> i32 {
        self.value.proto.proto().number()
    }

    // name of enum variant in generated rust code
    pub fn rust_name_inner(&self) -> RustIdent {
        self.value.rust_name()
    }

    pub fn rust_name_outer(&self) -> RustIdentWithPath {
        self.enum_rust_name
            .to_path()
            .with_ident(self.rust_name_inner())
    }
}

// Codegen for enum definition
pub(crate) struct EnumGen<'a> {
    enum_with_scope: &'a EnumWithScope<'a>,
    file_index: &'a FileIndex,
    type_name: RustIdentWithPath,
    lite_runtime: bool,
    customize: CustomizeElemCtx<'a>,
    path: &'a [i32],
    info: Option<&'a SourceCodeInfo>,
}

impl<'a> EnumGen<'a> {
    pub fn new(
        enum_with_scope: &'a EnumWithScope<'a>,
        file_index: &'a FileIndex,
        customize: &CustomizeElemCtx<'a>,
        _root_scope: &RootScope,
        path: &'a [i32],
        info: Option<&'a SourceCodeInfo>,
    ) -> EnumGen<'a> {
        let customize = customize.child(
            &customize_from_rustproto_for_enum(enum_with_scope.en.proto().options.get_or_default()),
            &enum_with_scope.en,
        );
        let lite_runtime = customize.for_elem.lite_runtime.unwrap_or_else(|| {
            enum_with_scope
                .scope()
                .file_descriptor()
                .options
                .get_or_default()
                .optimize_for()
                == file_options::OptimizeMode::LITE_RUNTIME
        });

        EnumGen {
            enum_with_scope,
            type_name: enum_with_scope.rust_name().to_path(),
            lite_runtime,
            customize,
            path,
            info,
            file_index,
        }
    }

    fn index_in_file(&self) -> u32 {
        self.file_index.enum_to_index[&self.enum_with_scope.protobuf_name_to_package()]
    }

    fn allow_alias(&self) -> bool {
        self.enum_with_scope
            .en
            .proto()
            .options
            .get_or_default()
            .allow_alias()
    }

    fn values_all(&self) -> Vec<EnumValueGen> {
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    fn values_unique(&self) -> Vec<EnumValueGen> {
        let mut used = HashSet::new();
        let mut r = Vec::new();
        for p in self.enum_with_scope.values() {
            if !used.insert(p.proto.proto().number()) {
                continue;
            }
            r.push(EnumValueGen::parse(p, &self.type_name));
        }
        r
    }

    pub fn write(&self, w: &mut CodeWriter) {
        self.write_enum(w);
        if self.allow_alias() {
            w.write_line("");
            self.write_impl_eq(w);
            w.write_line("");
            self.write_impl_hash(w);
        }
        w.write_line("");
        self.write_impl_enum(w);
        if !self.lite_runtime {
            w.write_line("");
            self.write_impl_enum_full(w);
        }
        w.write_line("");
        self.write_impl_default(w);
        w.write_line("");
        self.write_impl_self(w);
    }

    fn write_impl_self(&self, w: &mut CodeWriter) {
        if !self.lite_runtime {
            w.impl_self_block(&format!("{}", self.type_name), |w| {
                self.write_generated_enum_descriptor_data(w);
            });
        }
    }

    fn write_enum(&self, w: &mut CodeWriter) {
        w.all_documentation(self.info, self.path);

        let mut derive = Vec::new();
        derive.push("Clone");
        derive.push("Copy");
        if !self.allow_alias() {
            derive.push("PartialEq");
        }
        derive.push("Eq");
        derive.push("Debug");
        if !self.allow_alias() {
            derive.push("Hash");
        } else {
            w.comment("Note: you cannot use pattern matching for enums with allow_alias option");
        }
        w.derive(&derive);
        let ref type_name = self.type_name;
        write_protoc_insertion_point_for_enum(
            w,
            &self.customize.for_elem,
            &self.enum_with_scope.en,
        );
        w.expr_block(&format!("pub enum {}", type_name), |w| {
            for value in self.values_all() {
                write_protoc_insertion_point_for_enum_value(
                    w,
                    &self.customize.for_children,
                    &value.value.proto,
                );
                if self.allow_alias() {
                    w.write_line(&format!(
                        "{}, // {}",
                        value.rust_name_inner(),
                        value.number()
                    ));
                } else {
                    w.write_line(&format!(
                        "{} = {},",
                        value.rust_name_inner(),
                        value.number()
                    ));
                }
            }
        });
    }

    fn write_fn_value(&self, w: &mut CodeWriter) {
        w.def_fn("value(&self) -> i32", |w| {
            if self.allow_alias() {
                w.match_expr("*self", |w| {
                    for value in self.values_all() {
                        w.case_expr(
                            &format!("{}", value.rust_name_outer()),
                            &format!("{}", value.number()),
                        );
                    }
                });
            } else {
                w.write_line("*self as i32")
            }
        });
    }

    fn write_impl_enum(&self, w: &mut CodeWriter) {
        let ref type_name = self.type_name;
        w.impl_for_block(
            &format!("{}::Enum", protobuf_crate_path(&self.customize.for_elem)),
            &format!("{}", type_name),
            |w| {
                self.write_fn_value(w);

                w.write_line("");
                let ref type_name = self.type_name;
                w.def_fn(
                    &format!(
                        "from_i32(value: i32) -> ::std::option::Option<{}>",
                        type_name
                    ),
                    |w| {
                        w.match_expr("value", |w| {
                            let values = self.values_unique();
                            for value in values {
                                w.write_line(&format!(
                                    "{} => ::std::option::Option::Some({}),",
                                    value.number(),
                                    value.rust_name_outer()
                                ));
                            }
                            w.write_line(&format!("_ => {}", EXPR_NONE));
                        });
                    },
                );

                w.write_line("");
                w.def_fn(&format!("values() -> &'static [Self]"), |w| {
                    w.write_line(&format!("static values: &'static [{}] = &[", type_name));
                    w.indented(|w| {
                        for value in self.values_all() {
                            w.write_line(&format!("{},", value.rust_name_outer()));
                        }
                    });
                    w.write_line("];");
                    w.write_line("values");
                });
            },
        );
    }

    fn write_impl_enum_full(&self, w: &mut CodeWriter) {
        let ref type_name = self.type_name;
        w.impl_for_block(
            &format!(
                "{}::EnumFull",
                protobuf_crate_path(&self.customize.for_elem)
            ),
            &format!("{}", type_name),
            |w| {
                self.write_enum_descriptor_static(w);
            },
        );
    }

    fn write_enum_descriptor_static(&self, w: &mut CodeWriter) {
        let sig = format!(
            "enum_descriptor_static() -> {}::reflect::EnumDescriptor",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.def_fn(&sig, |w| {
            w.write_line(&format!(
                "{}::reflect::EnumDescriptor::new_generated_2({}(), {})",
                protobuf_crate_path(&self.customize.for_elem),
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse()
                    .append_ident("file_descriptor".into()),
                self.index_in_file(),
            ));
        });
    }

    fn write_generated_enum_descriptor_data(&self, w: &mut CodeWriter) {
        let sig = format!(
            "generated_enum_descriptor_data() -> {}::reflect::GeneratedEnumDescriptorData",
            protobuf_crate_path(&self.customize.for_elem)
        );
        w.fn_block(
            Visibility::Path(
                self.enum_with_scope
                    .scope()
                    .rust_path_to_file()
                    .to_reverse(),
            ),
            &sig,
            |w| {
                w.write_line(&format!(
                    "{}::reflect::GeneratedEnumDescriptorData::new_2::<{}>(\"{}\", {})",
                    protobuf_crate_path(&self.customize.for_elem),
                    self.type_name,
                    self.enum_with_scope.name_to_package(),
                    self.index_in_file(),
                ));
            },
        );
    }

    fn write_impl_eq(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block(
            "::std::cmp::PartialEq",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("eq(&self, other: &Self) -> bool", |w| {
                    w.write_line(&format!(
                        "{}::Enum::value(self) == {}::Enum::value(other)",
                        protobuf_crate_path(&self.customize.for_elem),
                        protobuf_crate_path(&self.customize.for_elem)
                    ));
                });
            },
        );
    }

    fn write_impl_hash(&self, w: &mut CodeWriter) {
        assert!(self.allow_alias());
        w.impl_for_block("::std::hash::Hash", &format!("{}", self.type_name), |w| {
            w.def_fn("hash<H : ::std::hash::Hasher>(&self, state: &mut H)", |w| {
                w.write_line(&format!(
                    "state.write_i32({}::Enum::value(self))",
                    protobuf_crate_path(&self.customize.for_elem)
                ));
            });
        });
    }

    fn write_impl_default(&self, w: &mut CodeWriter) {
        let first_value = &self.enum_with_scope.values()[0];
        if first_value.proto.proto().number() != 0 {
            // This warning is emitted only for proto2
            // (because in proto3 first enum variant number is always 0).
            // `Default` implemented unconditionally to simplify certain
            // generic operations, e. g. reading a map.
            // Also, note that even in proto2 some operations fallback to
            // first enum value, e. g. `get_xxx` for unset field,
            // so this implementation is not completely unreasonable.
            w.comment("Note, `Default` is implemented although default value is not 0");
        }
        w.impl_for_block(
            "::std::default::Default",
            &format!("{}", self.type_name),
            |w| {
                w.def_fn("default() -> Self", |w| {
                    w.write_line(&format!(
                        "{}::{}",
                        &self.type_name,
                        &first_value.rust_name()
                    ))
                });
            },
        );
    }
}
<|endoftext|>


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

use attr::AttrMetaMethods;
use diagnostic::SpanHandler;
use fold::Folder;
use {ast, fold, attr};
use codemap::Spanned;
use ptr::P;

/// A folder that strips out items that do not belong in the current
/// configuration.
struct Context<'a> {
    in_cfg: |attrs: &[ast::Attribute]|: 'a -> bool,
}

// Support conditional compilation by transforming the AST, stripping out
// any items that do not belong in the current configuration
pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate) -> ast::Crate {
    let config = krate.config.clone();
    strip_items(krate, |attrs| in_cfg(diagnostic, config.as_slice(), attrs))
}

impl<'a> fold::Folder for Context<'a> {
    fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
        fold_mod(self, module)
    }
    fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
        fold_block(self, block)
    }
    fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
        fold_foreign_mod(self, foreign_mod)
    }
    fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
        fold_item_underscore(self, item)
    }
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
        fold_expr(self, expr)
    }
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
    }
}

pub fn strip_items(krate: ast::Crate,
                   in_cfg: |attrs: &[ast::Attribute]| -> bool)
                   -> ast::Crate {
    let mut ctxt = Context {
        in_cfg: in_cfg,
    };
    ctxt.fold_crate(krate)
}

fn filter_view_item(cx: &mut Context, view_item: ast::ViewItem) -> Option<ast::ViewItem> {
    if view_item_in_cfg(cx, &view_item) {
        Some(view_item)
    } else {
        None
    }
}

fn fold_mod(cx: &mut Context, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mod {
    ast::Mod {
        inner: inner,
        view_items: view_items.into_iter().filter_map(|a| {
            filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
        }).collect(),
        items: items.into_iter().filter_map(|a| {
            if item_in_cfg(cx, &*a) {
                Some(cx.fold_item(a))
            } else {
                None
            }
        }).flat_map(|x| x.into_iter()).collect()
    }
}

fn filter_foreign_item(cx: &mut Context, item: P<ast::ForeignItem>)
                       -> Option<P<ast::ForeignItem>> {
    if foreign_item_in_cfg(cx, &*item) {
        Some(item)
    } else {
        None
    }
}

fn fold_foreign_mod(cx: &mut Context, ast::ForeignMod {abi, view_items, items}: ast::ForeignMod)
                    -> ast::ForeignMod {
    ast::ForeignMod {
        abi: abi,
        view_items: view_items.into_iter().filter_map(|a| {
            filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
        }).collect(),
        items: items.into_iter()
                    .filter_map(|a| filter_foreign_item(cx, a))
                    .collect()
    }
}

fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ {
    let item = match item {
        ast::ItemImpl(a, b, c, impl_items) => {
            let impl_items = impl_items.into_iter()
                                       .filter(|ii| impl_item_in_cfg(cx, ii))
                                       .collect();
            ast::ItemImpl(a, b, c, impl_items)
        }
        ast::ItemTrait(a, b, c, methods) => {
            let methods = methods.into_iter()
                                 .filter(|m| trait_method_in_cfg(cx, m))
                                 .collect();
            ast::ItemTrait(a, b, c, methods)
        }
        ast::ItemStruct(def, generics) => {
            ast::ItemStruct(fold_struct(cx, def), generics)
        }
        ast::ItemEnum(def, generics) => {
            let mut variants = def.variants.into_iter().filter_map(|v| {
                if !(cx.in_cfg)(v.node.attrs.as_slice()) {
                    None
                } else {
                    Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind,
                                                              disr_expr, vis}, span}| {
                        Spanned {
                            node: ast::Variant_ {
                                id: id,
                                name: name,
                                attrs: attrs,
                                kind: match kind {
                                    ast::TupleVariantKind(..) => kind,
                                    ast::StructVariantKind(def) => {
                                        ast::StructVariantKind(fold_struct(cx, def))
                                    }
                                },
                                disr_expr: disr_expr,
                                vis: vis
                            },
                            span: span
                        }
                    }))
                }
            });
            ast::ItemEnum(ast::EnumDef {
                variants: variants.collect(),
            }, generics)
        }
        item => item,
    };

    fold::noop_fold_item_underscore(item, cx)
}

fn fold_struct(cx: &mut Context, def: P<ast::StructDef>) -> P<ast::StructDef> {
    def.map(|ast::StructDef { fields, ctor_id }| {
        ast::StructDef {
            fields: fields.into_iter().filter(|m| {
                (cx.in_cfg)(m.node.attrs.as_slice())
            }).collect(),
            ctor_id: ctor_id,
        }
    })
}

fn retain_stmt(cx: &mut Context, stmt: &ast::Stmt) -> bool {
    match stmt.node {
        ast::StmtDecl(ref decl, _) => {
            match decl.node {
                ast::DeclItem(ref item) => {
                    item_in_cfg(cx, &**item)
                }
                _ => true
            }
        }
        _ => true
    }
}

fn fold_block(cx: &mut Context, b: P<ast::Block>) -> P<ast::Block> {
    b.map(|ast::Block {id, view_items, stmts, expr, rules, span}| {
        let resulting_stmts: Vec<P<ast::Stmt>> =
            stmts.into_iter().filter(|a| retain_stmt(cx, &**a)).collect();
        let resulting_stmts = resulting_stmts.into_iter()
            .flat_map(|stmt| cx.fold_stmt(stmt).into_iter())
            .collect();
        let filtered_view_items = view_items.into_iter().filter_map(|a| {
            filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
        }).collect();
        ast::Block {
            id: id,
            view_items: filtered_view_items,
            stmts: resulting_stmts,
            expr: expr.map(|x| cx.fold_expr(x)),
            rules: rules,
            span: span,
        }
    })
}

fn fold_expr(cx: &mut Context, expr: P<ast::Expr>) -> P<ast::Expr> {
    expr.map(|ast::Expr {id, span, node}| {
        fold::noop_fold_expr(ast::Expr {
            id: id,
            node: match node {
                ast::ExprMatch(m, arms, source) => {
                    ast::ExprMatch(m, arms.into_iter()
                                        .filter(|a| (cx.in_cfg)(a.attrs.as_slice()))
                                        .collect(), source)
                }
                _ => node
            },
            span: span
        }, cx)
    })
}

fn item_in_cfg(cx: &mut Context, item: &ast::Item) -> bool {
    return (cx.in_cfg)(item.attrs.as_slice());
}

fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool {
    return (cx.in_cfg)(item.attrs.as_slice());
}

fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
    return (cx.in_cfg)(item.attrs.as_slice());
}

fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool {
    match *meth {
        ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
        ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
        ast::TypeTraitItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()),
    }
}

fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool {
    match *impl_item {
        ast::MethodImplItem(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
        ast::TypeImplItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()),
    }
}

// Determine if an item should be translated in the current crate
// configuration based on the item's attributes
fn in_cfg(diagnostic: &SpanHandler, cfg: &[P<ast::MetaItem>], attrs: &[ast::Attribute]) -> bool {
    let mut in_cfg = false;
    let mut seen_cfg = false;
    for attr in attrs.iter() {
        let mis = match attr.node.value.node {
            ast::MetaList(_, ref mis) if attr.check_name("cfg") => mis,
            _ => continue
        };

        if mis.len() != 1 {
            diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
            return false;
        }

        if seen_cfg {
            diagnostic.span_err(attr.span, "The semantics of multiple `#[cfg(..)]` attributes on \
                                            same item are changing from the union of the cfgs to \
                                            the intersection of the cfgs. Change `#[cfg(a)] \
                                            #[cfg(b)]` to `#[cfg(any(a, b))]`.");
            return false;
        }

        seen_cfg = true;
        in_cfg |= attr::cfg_matches(diagnostic, cfg, &*mis[0]);
    }
    in_cfg | !seen_cfg
}

<commit_msg>rollup merge of #18326 : sfackler/cfg-final<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use attr::AttrMetaMethods;
use diagnostic::SpanHandler;
use fold::Folder;
use {ast, fold, attr};
use codemap::Spanned;
use ptr::P;

/// A folder that strips out items that do not belong in the current
/// configuration.
struct Context<'a> {
    in_cfg: |attrs: &[ast::Attribute]|: 'a -> bool,
}

// Support conditional compilation by transforming the AST, stripping out
// any items that do not belong in the current configuration
pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate) -> ast::Crate {
    let config = krate.config.clone();
    strip_items(krate, |attrs| in_cfg(diagnostic, config.as_slice(), attrs))
}

impl<'a> fold::Folder for Context<'a> {
    fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
        fold_mod(self, module)
    }
    fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
        fold_block(self, block)
    }
    fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
        fold_foreign_mod(self, foreign_mod)
    }
    fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
        fold_item_underscore(self, item)
    }
    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
        fold_expr(self, expr)
    }
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
    }
}

pub fn strip_items(krate: ast::Crate,
                   in_cfg: |attrs: &[ast::Attribute]| -> bool)
                   -> ast::Crate {
    let mut ctxt = Context {
        in_cfg: in_cfg,
    };
    ctxt.fold_crate(krate)
}

fn filter_view_item(cx: &mut Context, view_item: ast::ViewItem) -> Option<ast::ViewItem> {
    if view_item_in_cfg(cx, &view_item) {
        Some(view_item)
    } else {
        None
    }
}

fn fold_mod(cx: &mut Context, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mod {
    ast::Mod {
        inner: inner,
        view_items: view_items.into_iter().filter_map(|a| {
            filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
        }).collect(),
        items: items.into_iter().filter_map(|a| {
            if item_in_cfg(cx, &*a) {
                Some(cx.fold_item(a))
            } else {
                None
            }
        }).flat_map(|x| x.into_iter()).collect()
    }
}

fn filter_foreign_item(cx: &mut Context, item: P<ast::ForeignItem>)
                       -> Option<P<ast::ForeignItem>> {
    if foreign_item_in_cfg(cx, &*item) {
        Some(item)
    } else {
        None
    }
}

fn fold_foreign_mod(cx: &mut Context, ast::ForeignMod {abi, view_items, items}: ast::ForeignMod)
                    -> ast::ForeignMod {
    ast::ForeignMod {
        abi: abi,
        view_items: view_items.into_iter().filter_map(|a| {
            filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
        }).collect(),
        items: items.into_iter()
                    .filter_map(|a| filter_foreign_item(cx, a))
                    .collect()
    }
}

fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ {
    let item = match item {
        ast::ItemImpl(a, b, c, impl_items) => {
            let impl_items = impl_items.into_iter()
                                       .filter(|ii| impl_item_in_cfg(cx, ii))
                                       .collect();
            ast::ItemImpl(a, b, c, impl_items)
        }
        ast::ItemTrait(a, b, c, methods) => {
            let methods = methods.into_iter()
                                 .filter(|m| trait_method_in_cfg(cx, m))
                                 .collect();
            ast::ItemTrait(a, b, c, methods)
        }
        ast::ItemStruct(def, generics) => {
            ast::ItemStruct(fold_struct(cx, def), generics)
        }
        ast::ItemEnum(def, generics) => {
            let mut variants = def.variants.into_iter().filter_map(|v| {
                if !(cx.in_cfg)(v.node.attrs.as_slice()) {
                    None
                } else {
                    Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind,
                                                              disr_expr, vis}, span}| {
                        Spanned {
                            node: ast::Variant_ {
                                id: id,
                                name: name,
                                attrs: attrs,
                                kind: match kind {
                                    ast::TupleVariantKind(..) => kind,
                                    ast::StructVariantKind(def) => {
                                        ast::StructVariantKind(fold_struct(cx, def))
                                    }
                                },
                                disr_expr: disr_expr,
                                vis: vis
                            },
                            span: span
                        }
                    }))
                }
            });
            ast::ItemEnum(ast::EnumDef {
                variants: variants.collect(),
            }, generics)
        }
        item => item,
    };

    fold::noop_fold_item_underscore(item, cx)
}

fn fold_struct(cx: &mut Context, def: P<ast::StructDef>) -> P<ast::StructDef> {
    def.map(|ast::StructDef { fields, ctor_id }| {
        ast::StructDef {
            fields: fields.into_iter().filter(|m| {
                (cx.in_cfg)(m.node.attrs.as_slice())
            }).collect(),
            ctor_id: ctor_id,
        }
    })
}

fn retain_stmt(cx: &mut Context, stmt: &ast::Stmt) -> bool {
    match stmt.node {
        ast::StmtDecl(ref decl, _) => {
            match decl.node {
                ast::DeclItem(ref item) => {
                    item_in_cfg(cx, &**item)
                }
                _ => true
            }
        }
        _ => true
    }
}

fn fold_block(cx: &mut Context, b: P<ast::Block>) -> P<ast::Block> {
    b.map(|ast::Block {id, view_items, stmts, expr, rules, span}| {
        let resulting_stmts: Vec<P<ast::Stmt>> =
            stmts.into_iter().filter(|a| retain_stmt(cx, &**a)).collect();
        let resulting_stmts = resulting_stmts.into_iter()
            .flat_map(|stmt| cx.fold_stmt(stmt).into_iter())
            .collect();
        let filtered_view_items = view_items.into_iter().filter_map(|a| {
            filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
        }).collect();
        ast::Block {
            id: id,
            view_items: filtered_view_items,
            stmts: resulting_stmts,
            expr: expr.map(|x| cx.fold_expr(x)),
            rules: rules,
            span: span,
        }
    })
}

fn fold_expr(cx: &mut Context, expr: P<ast::Expr>) -> P<ast::Expr> {
    expr.map(|ast::Expr {id, span, node}| {
        fold::noop_fold_expr(ast::Expr {
            id: id,
            node: match node {
                ast::ExprMatch(m, arms, source) => {
                    ast::ExprMatch(m, arms.into_iter()
                                        .filter(|a| (cx.in_cfg)(a.attrs.as_slice()))
                                        .collect(), source)
                }
                _ => node
            },
            span: span
        }, cx)
    })
}

fn item_in_cfg(cx: &mut Context, item: &ast::Item) -> bool {
    return (cx.in_cfg)(item.attrs.as_slice());
}

fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool {
    return (cx.in_cfg)(item.attrs.as_slice());
}

fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
    return (cx.in_cfg)(item.attrs.as_slice());
}

fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool {
    match *meth {
        ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
        ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
        ast::TypeTraitItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()),
    }
}

fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool {
    match *impl_item {
        ast::MethodImplItem(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
        ast::TypeImplItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()),
    }
}

// Determine if an item should be translated in the current crate
// configuration based on the item's attributes
fn in_cfg(diagnostic: &SpanHandler, cfg: &[P<ast::MetaItem>], attrs: &[ast::Attribute]) -> bool {
    attrs.iter().all(|attr| {
        let mis = match attr.node.value.node {
            ast::MetaList(_, ref mis) if attr.check_name("cfg") => mis,
            _ => return true
        };

        if mis.len() != 1 {
            diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
            return true;
        }

        attr::cfg_matches(diagnostic, cfg, &*mis[0])
    })
}

<|endoftext|>


<commit_before>use super::{RootMove, MAX_MOVES};
use sync::GuardedBool;

use pleco::{MoveList, Board, PieceType, BitMove};

use std::slice;
use std::ops::{Deref,DerefMut,Index,IndexMut};
use std::iter::{Iterator,IntoIterator,FusedIterator,TrustedLen,ExactSizeIterator};
use std::ptr;

use std::mem::transmute;
use std::sync::atomic::{AtomicU16,Ordering,fence,AtomicBool};

use rand;
use rand::Rng;

pub struct RawRootMoveList {
    len: u32, // 4 bytes
    depth_completed: AtomicU16, // 2 bytes
    stop: AtomicBool,
    kill: AtomicBool,
    pub finished: GuardedBool, // 1 byte
    moves: [RootMove; MAX_MOVES], // 4096 bytes
}

impl RawRootMoveList {
    pub fn init(&mut self) {
        self.depth_completed = AtomicU16::new(0);
        self.stop.store(true, Ordering::SeqCst);
        self.kill.store(false, Ordering::SeqCst);
        self.len = 0;
        unsafe {
            let f = &mut self.finished;
            ptr::write_volatile(f, GuardedBool::new(true));
        }
    }
}

pub struct RootMoveList {
    pub moves: *mut RawRootMoveList
}

impl Clone for RootMoveList {
    fn clone(&self) -> Self {
        RootMoveList {
            moves: self.moves
        }
    }
}

unsafe impl Send for RootMoveList {}

impl RootMoveList {
    pub unsafe fn init(&mut self) {
        (*self.moves).init();
    }

    #[inline]
    pub fn len(&self) -> usize {
        unsafe {(*self.moves).len as usize}
    }

    pub fn clone_from_other(&mut self, other: &RootMoveList) {
        unsafe {
            (*self.moves).len = other.len() as u32;
            let self_moves: *mut [RootMove; MAX_MOVES] = transmute::<*mut RootMove, *mut [RootMove; MAX_MOVES]>((*self.moves).moves.as_mut_ptr());
            let other_moves: *mut [RootMove; MAX_MOVES] =  transmute::<*mut RootMove, *mut [RootMove; MAX_MOVES]>((*other.moves).moves.as_mut_ptr());
            ptr::copy_nonoverlapping(other_moves, self_moves, 1);
        }
    }

    pub fn replace(&mut self, moves: &MoveList) {
        unsafe {
            (*self.moves).len = moves.len() as u32;
            for (i, mov) in moves.iter().enumerate() {
                self[i] = RootMove::new(*mov);
            }
        }
    }

    #[inline]
    pub fn rollback(&mut self) {
        self.iter_mut()
            .for_each(|b| b.prev_score = b.score);
    }

    #[inline]
    pub fn first(&mut self) -> &mut RootMove {
        unsafe {
            self.get_unchecked_mut(0)
        }
    }

    #[inline]
    pub fn depth_completed(self) -> u16 {
        unsafe {
            (*self.moves).depth_completed.load(Ordering::SeqCst)
        }
    }

    #[inline]
    pub fn set_depth_completed(&mut self, depth: u16) {
        unsafe {
            fence(Ordering::SeqCst);
            (*self.moves).depth_completed.store(depth, Ordering::SeqCst);
        }
    }

    #[inline]
    pub fn set_finished(&mut self, finished: bool) {
        unsafe {
            (*self.moves).finished.set(finished);
        }
    }

    pub fn load_stop(&self) -> bool{
        unsafe {
            (*self.moves).stop.load(Ordering::SeqCst)
        }
    }

    pub fn set_stop(&mut self, stop: bool) {
        unsafe {
            (*self.moves).stop.store(stop, Ordering::Relaxed);
        }
    }

    pub fn kill(&mut self) {
        unsafe {
            (*self.moves).kill.store(true, Ordering::Relaxed);
        }
    }

    pub fn get_kill(&self) -> bool {
        unsafe {
            (*self.moves).kill.load(Ordering::SeqCst)
        }
    }

    #[inline]
    pub fn mvv_laa_sort(&mut self, board: &Board) {
        self.sort_by_key(|root_move| {
            let a = root_move.bit_move;
            let piece = board.piece_at_sq((a).get_src()).unwrap();

            if a.is_capture() {
                piece.value() - board.captured_piece(a).unwrap().value()
            } else if a.is_castle() {
                1
            } else if piece == PieceType::P {
                if a.is_double_push().0 {
                    2
                } else {
                    3
                }
            } else {
                4
            }
        });
    }

    #[inline]
    pub fn shuffle(&mut self, thread_id: usize, board: &Board) {
        if thread_id == 0 || thread_id >= 20 {
            self.mvv_laa_sort(board);
        } else {
            rand::thread_rng().shuffle(self.as_mut());
        }
    }

    pub fn to_list(&self) -> MoveList {
        let vec =  self.iter().map(|m| m.bit_move).collect::<Vec<BitMove>>();
        MoveList::from(vec)
    }

    pub fn prev_best_score(&self) -> i32 {
        unsafe {
            self.get_unchecked(0).prev_score
        }
    }

    pub fn insert_score_depth(&mut self, index: usize, score: i32, depth: u16) {
        unsafe {
            let rm: &mut RootMove = self.get_unchecked_mut(index);
            rm.score = score;
            rm.depth_reached = depth;

        }
    }

    pub fn insert_score(&mut self, index: usize, score: i32) {
        unsafe {
            let rm: &mut RootMove = self.get_unchecked_mut(index);
            rm.score = score;
        }
    }
}

impl Deref for RootMoveList {
    type Target = [RootMove];

    #[inline]
    fn deref(&self) -> &[RootMove] {
        unsafe {
            let p = (*self.moves).moves.as_ptr();
            slice::from_raw_parts(p, self.len())
        }
    }
}

impl DerefMut for RootMoveList {
    #[inline]
    fn deref_mut(&mut self) -> &mut [RootMove] {
        unsafe {
            let p = (*self.moves).moves.as_mut_ptr();
            slice::from_raw_parts_mut(p, self.len())
        }
    }
}

impl Index<usize> for RootMoveList {
    type Output = RootMove;

    #[inline]
    fn index(&self, index: usize) -> &RootMove {
        &(**self)[index]
    }
}

impl IndexMut<usize> for RootMoveList {
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut RootMove {
        &mut (**self)[index]
    }
}

pub struct MoveIter<'a> {
    movelist: &'a RootMoveList,
    idx: usize,
    len: usize
}

impl<'a> Iterator for MoveIter<'a> {
    type Item = RootMove;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.len {
            None
        } else {
            unsafe {
                let m = *self.movelist.get_unchecked(self.idx);
                self.idx += 1;
                Some(m)
            }

        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.idx, Some(self.len - self.idx))
    }
}

impl<'a> IntoIterator for &'a RootMoveList {
    type Item = RootMove;
    type IntoIter = MoveIter<'a>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        MoveIter {
            movelist: &self,
            idx: 0,
            len: self.len()
        }
    }
}

impl<'a> ExactSizeIterator for MoveIter<'a> {}

impl<'a> FusedIterator for MoveIter<'a> {}

unsafe impl<'a> TrustedLen for MoveIter<'a> {}<commit_msg>Changed atomic orderings around<commit_after>use super::{RootMove, MAX_MOVES};
use sync::GuardedBool;

use pleco::{MoveList, Board, PieceType, BitMove};

use std::slice;
use std::ops::{Deref,DerefMut,Index,IndexMut};
use std::iter::{Iterator,IntoIterator,FusedIterator,TrustedLen,ExactSizeIterator};
use std::ptr;

use std::mem::transmute;
use std::sync::atomic::{AtomicU16,Ordering,fence,AtomicBool,AtomicUsize};

use rand;
use rand::Rng;

pub struct RawRootMoveList {
    len: AtomicUsize,
    depth_completed: AtomicU16,
    stop: AtomicBool,
    kill: AtomicBool,
    pub finished: GuardedBool,
    moves: [RootMove; MAX_MOVES],
}

impl RawRootMoveList {
    pub fn init(&mut self) {
        self.depth_completed = AtomicU16::new(0);
        self.stop.store(true, Ordering::SeqCst);
        self.kill.store(false, Ordering::SeqCst);
        self.len = AtomicUsize::new(0);
        unsafe {
            let f = &mut self.finished;
            ptr::write_volatile(f, GuardedBool::new(true));
        }
    }
}

pub struct RootMoveList {
    pub moves: *mut RawRootMoveList
}

impl Clone for RootMoveList {
    fn clone(&self) -> Self {
        RootMoveList {
            moves: self.moves
        }
    }
}

unsafe impl Send for RootMoveList {}

impl RootMoveList {
    pub unsafe fn init(&mut self) {
        (*self.moves).init();
    }

    #[inline]
    pub fn len(&self) -> usize {
        unsafe {(*self.moves).len.load(Ordering::Release)}
    }

    pub fn clone_from_other(&mut self, other: &RootMoveList) {
        unsafe {
            (*self.moves).len.store(other.len(), Ordering::Acquire);
            let self_moves: *mut [RootMove; MAX_MOVES] = transmute::<*mut RootMove, *mut [RootMove; MAX_MOVES]>((*self.moves).moves.as_mut_ptr());
            let other_moves: *mut [RootMove; MAX_MOVES] =  transmute::<*mut RootMove, *mut [RootMove; MAX_MOVES]>((*other.moves).moves.as_mut_ptr());
            ptr::copy_nonoverlapping(other_moves, self_moves, 1);
        }
    }

    pub fn replace(&mut self, moves: &MoveList) {
        unsafe {
            (*self.moves).len.store(moves.len(), Ordering::Acquire);
            for (i, mov) in moves.iter().enumerate() {
                self[i] = RootMove::new(*mov);
            }
        }
    }

    #[inline]
    pub fn rollback(&mut self) {
        self.iter_mut()
            .for_each(|b| b.prev_score = b.score);
    }

    #[inline]
    pub fn first(&mut self) -> &mut RootMove {
        unsafe {
            self.get_unchecked_mut(0)
        }
    }

    #[inline]
    pub fn depth_completed(self) -> u16 {
        unsafe {
            (*self.moves).depth_completed.load(Ordering::SeqCst)
        }
    }

    #[inline]
    pub fn set_depth_completed(&mut self, depth: u16) {
        unsafe {
            fence(Ordering::SeqCst);
            (*self.moves).depth_completed.store(depth, Ordering::SeqCst);
        }
    }

    #[inline]
    pub fn set_finished(&mut self, finished: bool) {
        unsafe {
            (*self.moves).finished.set(finished);
        }
    }

    pub fn load_stop(&self) -> bool{
        unsafe {
            (*self.moves).stop.load(Ordering::SeqCst)
        }
    }

    pub fn set_stop(&mut self, stop: bool) {
        unsafe {
            (*self.moves).stop.store(stop, Ordering::Relaxed);
        }
    }

    pub fn kill(&mut self) {
        unsafe {
            (*self.moves).kill.store(true, Ordering::Relaxed);
        }
    }

    pub fn get_kill(&self) -> bool {
        unsafe {
            (*self.moves).kill.load(Ordering::SeqCst)
        }
    }

    #[inline]
    pub fn mvv_laa_sort(&mut self, board: &Board) {
        self.sort_by_key(|root_move| {
            let a = root_move.bit_move;
            let piece = board.piece_at_sq((a).get_src()).unwrap();

            if a.is_capture() {
                piece.value() - board.captured_piece(a).unwrap().value()
            } else if a.is_castle() {
                1
            } else if piece == PieceType::P {
                if a.is_double_push().0 {
                    2
                } else {
                    3
                }
            } else {
                4
            }
        });
    }

    #[inline]
    pub fn shuffle(&mut self, thread_id: usize, board: &Board) {
        if thread_id == 0 || thread_id >= 20 {
            self.mvv_laa_sort(board);
        } else {
            rand::thread_rng().shuffle(self.as_mut());
        }
    }

    pub fn to_list(&self) -> MoveList {
        let vec =  self.iter().map(|m| m.bit_move).collect::<Vec<BitMove>>();
        MoveList::from(vec)
    }

    pub fn prev_best_score(&self) -> i32 {
        unsafe {
            self.get_unchecked(0).prev_score
        }
    }

    pub fn insert_score_depth(&mut self, index: usize, score: i32, depth: u16) {
        unsafe {
            let rm: &mut RootMove = self.get_unchecked_mut(index);
            rm.score = score;
            rm.depth_reached = depth;

        }
    }

    pub fn insert_score(&mut self, index: usize, score: i32) {
        unsafe {
            let rm: &mut RootMove = self.get_unchecked_mut(index);
            rm.score = score;
        }
    }
}

impl Deref for RootMoveList {
    type Target = [RootMove];

    #[inline]
    fn deref(&self) -> &[RootMove] {
        unsafe {
            let p = (*self.moves).moves.as_ptr();
            slice::from_raw_parts(p, self.len())
        }
    }
}

impl DerefMut for RootMoveList {
    #[inline]
    fn deref_mut(&mut self) -> &mut [RootMove] {
        unsafe {
            let p = (*self.moves).moves.as_mut_ptr();
            slice::from_raw_parts_mut(p, self.len())
        }
    }
}

impl Index<usize> for RootMoveList {
    type Output = RootMove;

    #[inline]
    fn index(&self, index: usize) -> &RootMove {
        &(**self)[index]
    }
}

impl IndexMut<usize> for RootMoveList {
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut RootMove {
        &mut (**self)[index]
    }
}

pub struct MoveIter<'a> {
    movelist: &'a RootMoveList,
    idx: usize,
    len: usize
}

impl<'a> Iterator for MoveIter<'a> {
    type Item = RootMove;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.idx >= self.len {
            None
        } else {
            unsafe {
                let m = *self.movelist.get_unchecked(self.idx);
                self.idx += 1;
                Some(m)
            }

        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.idx, Some(self.len - self.idx))
    }
}

impl<'a> IntoIterator for &'a RootMoveList {
    type Item = RootMove;
    type IntoIter = MoveIter<'a>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        MoveIter {
            movelist: &self,
            idx: 0,
            len: self.len()
        }
    }
}

impl<'a> ExactSizeIterator for MoveIter<'a> {}

impl<'a> FusedIterator for MoveIter<'a> {}

unsafe impl<'a> TrustedLen for MoveIter<'a> {}<|endoftext|>


<commit_before><commit_msg>Fix for libsyntax change in 67390c0c3 2018-08-14<commit_after><|endoftext|>