<commit_before>use std::marker::PhantomData;
use std::sync::atomic::{self, Ordering};
use std::{ptr, mem};

use super::{Owned, Shared, Guard};

/// Convert `Option<Shared<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_shared_into_raw<T>(val: Option<Shared<T>>) -> *mut T {
    val.map(|p| p.as_raw()).unwrap_or(ptr::null_mut())
}

/// Convert `Option<Owned<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_owned_into_raw<T>(val: Option<Owned<T>>) -> *mut T {
    let ptr = val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut());
    mem::forget(val);
    ptr
}

/// Convert `&Option<Owned<T>>` into `*mut T`.
///
/// `&None` maps to the null pointer.
#[inline]
fn opt_owned_as_raw<T>(val: &Option<Owned<T>>) -> *mut T {
    val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut())
}

/// Like `std::sync::atomic::AtomicPtr`.
///
/// Provides atomic access to a (nullable) pointer of type `T`, interfacing with
/// the `Owned` and `Shared` types.
#[derive(Debug)]
pub struct Atomic<T> {
    ptr: atomic::AtomicPtr<T>,
    _marker: PhantomData<*const ()>,
}

impl<T> Atomic<T> {
    /// Create a new, null atomic pointer.
    #[cfg(feature = "nightly")]
    pub const fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: PhantomData,
        }
    }

    #[cfg(not(feature = "nightly"))]
    pub fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: PhantomData,
        }
    }

    /// Create a new atomic pointer.
    ///
    /// This allocates `data` on the heap and creates an atomic pointer to it.
    pub fn new(data: T) -> Atomic<T> {
        Atomic {
            // As the data has to be stored _somewhere_, we have to allocate it to the heap.
            ptr: atomic::AtomicPtr::new(Box::into_raw(Box::new(data))),
            _marker: PhantomData,
        }
    }

    /// Do an atomic load with a given memory ordering.
    ///
    /// In order to perform the load, we must pass in a borrow of a `Guard`. This is a way of
    /// guaranteeing that the thread has pinned the epoch for the entire lifetime `'a`. In return,
    /// you get an optional `Shared` pointer back (`None` if the `Atomic` is currently null), with
    /// lifetime tied to the guard.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Release` or `AcqRel`.
    pub fn load<'a>(&self, ord: Ordering, _: &'a Guard) -> Option<Shared<'a, T>> {
        unsafe { Shared::from_raw(self.ptr.load(ord)) }
    }

    /// Do an atomic store with a given memory ordering.
    ///
    /// This transfers ownership of the given `Owned` pointer, if any. Since no lifetime
    /// information is acquired, no `Guard` value is needed.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store(&self, val: Option<Owned<T>>, ord: Ordering) {
        self.ptr.store(opt_owned_into_raw(val), ord)
    }

    /// Do an atomic store with the given memory ordering and get a shared reference.
    ///
    /// This transfers ownership of the given `Owned` pointer, yielding a `Shared` reference to it.
    /// Since the reference is valid only for the curent epoch, it's lifetime is tied to a `Guard`
    /// value.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_and_ref<'a>(&self, val: Owned<T>, ord: Ordering, _: &'a Guard) -> Shared<'a, T> {
        unsafe {
            let shared = Shared::from_owned(val);
            self.store_shared(Some(shared), ord);
            shared
        }
    }

    /// Do an atomic store of a `Shared` pointer with a given memory ordering.
    ///
    /// This operation does not require a guard, because it does not yield any new information
    /// about the lifetime of a pointer.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_shared(&self, val: Option<Shared<T>>, ord: Ordering) {
        self.ptr.store(opt_shared_into_raw(val), ord)
    }

    /// Atomically compare the value against `old` and swap it with `new` if matching.
    ///
    /// This is commonly refered to as 'CAS'. `self` is compared to `old`. If equal, `self` is set
    /// to `new` and `Ok(())` returned. Otherwise, `Err(actual_value)` is returned (with
    /// `actual_value` being the read value of `self`).
    ///
    /// All this is done atomically according to the atomic ordering specified in `ord`.
    pub fn compare_and_swap<'a>(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering, _: &'a Guard)
               -> Result<(), Option<Shared<'a, T>>> {
        let old = opt_shared_into_raw(old);
        let found = self.ptr.compare_and_swap(old, opt_shared_into_raw(new), ord);

        if found == old {
            Ok(())
        } else {
            Err(unsafe { Shared::from_raw(found) })
        }
    }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering.
    ///
    /// As with `store`, this operation does not require a guard; it produces no new lifetime
    /// information. The `Result` indicates whether the CAS succeeded; if not, ownership of the
    /// `new` pointer is returned to the caller.
    pub fn compare_and_set(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
               -> Result<(), Option<Owned<T>>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old),
                                     opt_owned_as_raw(&new),
                                     ord) == opt_shared_into_raw(old) {
            mem::forget(new);
            Ok(())
        } else {
            Err(new)
        }
   }

    /// Renamed to `compare_and_set`.
    #[deprecated]
    pub fn cas(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
               -> Result<(), Option<Owned<T>>> {
        self.compare_and_set(old, new, ord)
    }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering and get
    /// a shared reference to it.
    ///
    /// This operation is analogous to `store_and_ref`.
    pub fn compare_and_set_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>,
                           ord: Ordering, _: &'a Guard)
                           -> Result<Shared<'a, T>, Owned<T>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old), new.as_raw(), ord)
            == opt_shared_into_raw(old)
        {
            Ok(unsafe { Shared::from_owned(new) })
        } else {
            Err(new)
        }
    }

    /// Renamed to `compare_and_set_ref`.
    #[deprecated]
    pub fn cas_and_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>,
                           ord: Ordering, guard: &'a Guard)
                           -> Result<Shared<'a, T>, Owned<T>> {
        self.compare_and_set_ref(old, new, ord, guard)
    }

    /// compare-and-set from a `Shared` to another `Shared` pointer with a given memory ordering.
    ///
    /// The boolean return value is `true` when the CAS is successful.
    pub fn compare_and_set_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
                      -> bool {
        self.ptr.compare_and_swap(opt_shared_into_raw(old),
                                  opt_shared_into_raw(new),
                                  ord) == opt_shared_into_raw(old)
    }

    /// Renamed to `compare_and_set_shared`.
    #[deprecated]
    pub fn cas_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
                      -> bool {
        self.compare_and_set_shared(old, new, ord)
    }

    /// Do an atomic swap with an `Owned` pointer with the given memory ordering.
    pub fn swap<'a>(&self, new: Option<Owned<T>>, ord: Ordering, _: &'a Guard)
                    -> Option<Shared<'a, T>> {
        unsafe { Shared::from_raw(self.ptr.swap(opt_owned_into_raw(new), ord)) }
    }

    /// Do an atomic swap with a `Shared` pointer with a given memory ordering.
    pub fn swap_shared<'a>(&self,
                           new: Option<Shared<T>>,
                           ord: Ordering,
                           _: &'a Guard)
                           -> Option<Shared<'a, T>> {
        unsafe { Shared::from_raw(self.ptr.swap(opt_shared_into_raw(new), ord)) }
    }
}

impl<T> Default for Atomic<T> {
    fn default() -> Atomic<T> {
        Atomic::null()
    }
}

unsafe impl<T: Sync> Send for Atomic<T> {}
unsafe impl<T: Sync> Sync for Atomic<T> {}
<commit_msg>Update the code style of the `Atomic<T>` impl.<commit_after>use std::marker::PhantomData;
use std::sync::atomic::{self, Ordering};
use std::{ptr, mem};

use super::{Owned, Shared, Guard};

/// Convert `Option<Shared<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_shared_into_raw<T>(val: Option<Shared<T>>) -> *mut T {
    // If `None`, return the null pointer.
    val.map(|p| p.as_raw()).unwrap_or(ptr::null_mut())
}

/// Convert `Option<Owned<T>>` into `*mut T`.
///
/// `None` maps to the null pointer.
#[inline]
fn opt_owned_into_raw<T>(val: Option<Owned<T>>) -> *mut T {
    // If `None`, return the null pointer.
    let ptr = val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut());
    // This is absolutely crucial in order to avoid the returned pointer from being dangling.
    mem::forget(val);

    ptr
}

/// Convert `&Option<Owned<T>>` into `*mut T`.
///
/// `&None` maps to the null pointer.
#[inline]
fn opt_owned_as_raw<T>(val: &Option<Owned<T>>) -> *mut T {
    // If `None`, return the null pointer.
    val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut())
}

/// Like `std::sync::atomic::AtomicPtr`.
///
/// Provides atomic access to a (nullable) pointer of type `T`, interfacing with
/// the `Owned` and `Shared` types.
#[derive(Debug)]
pub struct Atomic<T> {
    /// The inner atomic pointer.
    ptr: atomic::AtomicPtr<T>,
    /// A phantom marker to fix certain compiler bugs.
    // TODO
    _marker: PhantomData<*const ()>,
}

impl<T> Atomic<T> {
    /// Create a new, null atomic pointer.
    #[cfg(feature = "nightly")]
    pub const fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: PhantomData,
        }
    }

    #[cfg(not(feature = "nightly"))]
    pub fn null() -> Atomic<T> {
        Atomic {
            ptr: atomic::AtomicPtr::new(ptr::null_mut()),
            _marker: PhantomData,
        }
    }

    /// Create a new atomic pointer.
    ///
    /// This allocates `data` on the heap and creates an atomic pointer to it.
    pub fn new(data: T) -> Atomic<T> {
        Atomic {
            // As the data has to be stored _somewhere_, we have to allocate it to the heap.
            ptr: atomic::AtomicPtr::new(Box::into_raw(Box::new(data))),
            _marker: PhantomData,
        }
    }

    /// Do an atomic load with a given memory ordering.
    ///
    /// In order to perform the load, we must pass in a borrow of a `Guard`. This is a way of
    /// guaranteeing that the thread has pinned the epoch for the entire lifetime `'a`. In return,
    /// you get an optional `Shared` pointer back (`None` if the `Atomic` is currently null), with
    /// lifetime tied to the guard.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Release` or `AcqRel`.
    pub fn load<'a>(&self, ord: Ordering, _: &'a Guard) -> Option<Shared<'a, T>> {
        unsafe { Shared::from_raw(self.ptr.load(ord)) }
    }

    /// Do an atomic store with a given memory ordering.
    ///
    /// This transfers ownership of the given `Owned` pointer, if any. Since no lifetime
    /// information is acquired, no `Guard` value is needed.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store(&self, val: Option<Owned<T>>, ord: Ordering) {
        self.ptr.store(opt_owned_into_raw(val), ord)
    }

    /// Do an atomic store with the given memory ordering and get a shared reference.
    ///
    /// This transfers ownership of the given `Owned` pointer, yielding a `Shared` reference to it.
    /// Since the reference is valid only for the curent epoch, it's lifetime is tied to a `Guard`
    /// value.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_and_ref<'a>(&self, val: Owned<T>, ord: Ordering, _: &'a Guard) -> Shared<'a, T> {
        unsafe {
            let shared = Shared::from_owned(val);
            self.store_shared(Some(shared), ord);
            shared
        }
    }

    /// Do an atomic store of a `Shared` pointer with a given memory ordering.
    ///
    /// This operation does not require a guard, because it does not yield any new information
    /// about the lifetime of a pointer.
    ///
    /// # Panics
    ///
    /// Panics if `ord` is `Acquire` or `AcqRel`.
    pub fn store_shared(&self, val: Option<Shared<T>>, ord: Ordering) {
        self.ptr.store(opt_shared_into_raw(val), ord)
    }

    /// Atomically compare the value against `old` and swap it with `new` if matching.
    ///
    /// This is commonly refered to as 'CAS'. `self` is compared to `old`. If equal, `self` is set
    /// to `new` and `Ok(())` returned. Otherwise, `Err(actual_value)` is returned (with
    /// `actual_value` being the read value of `self`).
    ///
    /// All this is done atomically according to the atomic ordering specified in `ord`.
    pub fn compare_and_swap<'a>(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering, _: &'a Guard)
        -> Result<(), Option<Shared<'a, T>>> {
        // Convert `old` into a raw pointer.
        let old = opt_shared_into_raw(old);
        // Compare it against `new`.
        let found = self.ptr.compare_and_swap(old, opt_shared_into_raw(new), ord);

        if found == old {
            // They matched, so the CAS succeeded.
            Ok(())
        } else {
            // They did not match, so we will return a shared pointer to the value.
            Err(unsafe { Shared::from_raw(found) })
        }
    }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering.
    ///
    /// As with `store`, this operation does not require a guard; it produces no new lifetime
    /// information. The `Result` indicates whether the CAS succeeded; if not, ownership of the
    /// `new` pointer is returned to the caller.
    pub fn compare_and_set(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
        -> Result<(), Option<Owned<T>>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old), opt_owned_as_raw(&new), ord)
            == opt_shared_into_raw(old) {
            // This is crucial to avoid `new`'s destructor being called, which could cause an
            // dangling pointer to leak into safe API.
            mem::forget(new);
            Ok(())
        } else {
            Err(new)
        }
   }

    /// Renamed to `compare_and_set`.
    #[deprecated]
    pub fn cas(&self, old: Option<Shared<T>>, new: Option<Owned<T>>, ord: Ordering)
        -> Result<(), Option<Owned<T>>> {
        self.compare_and_set(old, new, ord)
    }

    /// Compare-and-set from a `Shared` to an `Owned` pointer with a given memory ordering and get
    /// a shared reference to it.
    ///
    /// This operation is analogous to `store_and_ref`.
    pub fn compare_and_set_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>, ord: Ordering, _: &'a Guard)
        -> Result<Shared<'a, T>, Owned<T>> {
        if self.ptr.compare_and_swap(opt_shared_into_raw(old), new.as_raw(), ord)
            == opt_shared_into_raw(old) {
            Ok(unsafe { Shared::from_owned(new) })
        } else {
            Err(new)
        }
    }

    /// Renamed to `compare_and_set_ref`.
    #[deprecated]
    pub fn cas_and_ref<'a>(&self, old: Option<Shared<T>>, new: Owned<T>, ord: Ordering, guard: &'a Guard)
        -> Result<Shared<'a, T>, Owned<T>> {
        self.compare_and_set_ref(old, new, ord, guard)
    }

    /// compare-and-set from a `Shared` to another `Shared` pointer with a given memory ordering.
    ///
    /// The boolean return value is `true` when the CAS is successful.
    pub fn compare_and_set_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
        -> bool {
        self.ptr.compare_and_swap(opt_shared_into_raw(old), opt_shared_into_raw(new), ord)
            == opt_shared_into_raw(old)
    }

    /// Renamed to `compare_and_set_shared`.
    #[deprecated]
    pub fn cas_shared(&self, old: Option<Shared<T>>, new: Option<Shared<T>>, ord: Ordering)
                      -> bool {
        self.compare_and_set_shared(old, new, ord)
    }

    /// Do an atomic swap with an `Owned` pointer with the given memory ordering.
    pub fn swap<'a>(&self, new: Option<Owned<T>>, ord: Ordering, _: &'a Guard)
                    -> Option<Shared<'a, T>> {
        unsafe { Shared::from_raw(self.ptr.swap(opt_owned_into_raw(new), ord)) }
    }

    /// Do an atomic swap with a `Shared` pointer with a given memory ordering.
    pub fn swap_shared<'a>(&self, new: Option<Shared<T>>, ord: Ordering, _: &'a Guard)
        -> Option<Shared<'a, T>> {
        unsafe { Shared::from_raw(self.ptr.swap(opt_shared_into_raw(new), ord)) }
    }
}

impl<T> Default for Atomic<T> {
    fn default() -> Atomic<T> {
        Atomic::null()
    }
}

unsafe impl<T: Sync> Send for Atomic<T> {}
unsafe impl<T: Sync> Sync for Atomic<T> {}
<|endoftext|>


<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.
  pub is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  pub length: u32,
  /// Block data containing one of the eight different types of metadata.
  pub data: Data,
}

impl Metadata {
  pub fn new(is_last: bool, length: u32, data: Data) -> Self {
    Metadata {
      is_last: is_last,
      length: length,
      data: data,
    }
  }
}

/// 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 {
  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],
    }
  }

  #[inline]
  pub fn is_varied_block_size(&self) -> bool {
    self.min_block_size != self.max_block_size
  }

  #[inline]
  pub fn is_fixed_block_size(&self) -> bool {
    self.min_block_size == self.max_block_size
  }
}

/// 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.
  DuringPerformace,
  /// 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::DuringPerformace   => "During Performace",
      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>Make length private<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.
  pub 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,
}

impl Metadata {
  pub fn new(is_last: bool, length: u32, data: Data) -> Self {
    Metadata {
      is_last: is_last,
      length: length,
      data: data,
    }
  }
}

/// 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 {
  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],
    }
  }

  #[inline]
  pub fn is_varied_block_size(&self) -> bool {
    self.min_block_size != self.max_block_size
  }

  #[inline]
  pub fn is_fixed_block_size(&self) -> bool {
    self.min_block_size == self.max_block_size
  }
}

/// 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.
  DuringPerformace,
  /// 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::DuringPerformace   => "During Performace",
      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>//! Iron's Middleware and Handler System
//!
//! Iron's Middleware system is best modeled with a diagram.
//!
//! ```plain
//! [b] = BeforeMiddleware
//! [a] = AfterMiddleware
//! [[h]] = AroundMiddleware
//! [h] = Handler
//! ```
//!
//! With no errors, the flow looks like:
//!
//! ```plain
//! [b] -> [b] -> [b] -> [[[[h]]]] -> [a] -> [a] -> [a] -> [a]
//! ```
//!
//! A request first travels through all BeforeMiddleware, then a Response is generated
//! by the Handler, which can be an arbitrary nesting of AroundMiddleware, then all
//! AfterMiddleware are called with both the Request and Response. After all AfterMiddleware
//! have been fired, the response is written back to the client.
//!
//! Iron's error handling system is pragmatic and focuses on tracking two pieces
//! of information for error receivers (other middleware):
//!
//! * The cause of the error
//! * The result (what to do about) the error.
//!
//! The cause of the error is represented simply by the error itself, and the result
//! of the error, representing the action to take in response to the error, is a complete
//! Response, which will be sent at the end of the error flow.
//!
//! When an error is thrown in Iron by any middleware or handler returning an `Err`
//! variant with an `IronError`, the flow of the Request switches to the error flow,
//! which proceeds to just call the `catch` method of middleware and sidesteps the
//! `Handler` entirely, since there is already a Response in the error.
//!
//! A Request can exit the error flow by returning an Ok from any of the catch methods.
//! This resumes the flow at the middleware immediately following the middleware which
//! handled the error. It is impossible to "go back" to an earlier middleware that was
//! skipped.
//!
//! Generally speaking, returning a 5XX error code means that the error flow should be
//! entered by raising an explicit error. Dealing with 4XX errors is trickier, since
//! the server may not want to recognize an error that is entirely the clients fault;
//! handling of 4XX error codes is up to to each application and middleware author.
//!
//! Middleware authors should be cognizant that their middleware may be skipped during
//! the error flow. Anything that *must* be done to each Request or Response should
//! be run during both the normal and error flow by implementing the `catch` method to
//! also do the necessary action.
//!

use std::any::Any;
use {Request, Response, IronResult, IronError};

/// `Handler`s are responsible for handling requests by creating Responses from Requests.
pub trait Handler: Send + Sync + Any {
    /// Produce a `Response` from a Request, with the possibility of error.
    fn handle(&self, &mut Request) -> IronResult<Response>;
}

/// `BeforeMiddleware` are fired before a `Handler` is called inside of a Chain.
///
/// `BeforeMiddleware` are responsible for doing request pre-processing that requires
/// the ability to change control-flow, such as authorization middleware, or for editing
/// the request by modifying the headers.
///
/// `BeforeMiddleware` only have access to the Request, if you need to modify or read
/// a Response, you will need `AfterMiddleware`. Middleware which wishes to send an
/// early response that is not an error cannot be `BeforeMiddleware`, but should
/// instead be `AroundMiddleware`.
pub trait BeforeMiddleware: Send + Sync + Any {
    /// Do whatever work this middleware should do with a `Request` object.
    fn before(&self, _: &mut Request) -> IronResult<()> { Ok(()) }

    /// Respond to an error thrown by a previous `BeforeMiddleware`.
    ///
    /// Returning a `Ok` will cause the request to resume the normal flow at the
    /// next `BeforeMiddleware`, or if this was the last `BeforeMiddleware`,
    /// at the `Handler`.
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<()> { Err(err) }
}

/// `AfterMiddleware` are fired after a `Handler` is called inside of a Chain.
///
/// `AfterMiddleware` receive both a `Request` and a `Response` and are responsible for doing
/// any response post-processing.
///
/// `AfterMiddleware` should *not* overwrite the contents of a Response. In
/// the common case, a complete response is generated by the Chain's `Handler` and
/// `AfterMiddleware` simply do post-processing of that Response, such as
/// adding headers or logging.
pub trait AfterMiddleware: Send + Sync + Any {
    /// Do whatever post-processing this middleware should do.
    fn after(&self, _: &mut Request, res: Response) -> IronResult<Response> {
        Ok(res)
    }

    /// Respond to an error thrown by previous `AfterMiddleware`, the `Handler`,
    /// or a `BeforeMiddleware`.
    ///
    /// Returning `Ok` will cause the request to resume the normal flow at the
    /// next `AfterMiddleware`.
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        Err(err)
    }
}

/// AroundMiddleware are used to wrap and replace the `Handler` in a `Chain`.
///
/// AroundMiddleware produce `Handler`s through their `around` method, which is
/// called once on insertion into a Chain or can be called manually outside of a
/// `Chain`.
pub trait AroundMiddleware {
    /// Produce a `Handler` from this `AroundMiddleware` given another `Handler`.
    ///
    /// Usually this means wrapping the handler and editing the `Request` on the
    /// way in and the `Response` on the way out.
    ///
    /// This is called only once, when an `AroundMiddleware` is added to a `Chain`
    /// using `Chain::around`, it is passed the `Chain`'s current `Handler`.
    fn around(self, handler: Box<Handler>) -> Box<Handler>;
}

/// The middleware chain used in Iron.
///
/// This is a canonical implementation of Iron's middleware system,
/// but Iron's infrastructure is flexible enough to allow alternate
/// systems.
pub struct Chain {
    befores: Vec<Box<BeforeMiddleware>>,
    afters: Vec<Box<AfterMiddleware>>,

    // Internal invariant: this is always Some
    handler: Option<Box<Handler>>
}

impl Chain {
    /// Construct a new ChainBuilder from a `Handler`.
    pub fn new<H: Handler>(handler: H) -> Chain {
        Chain {
            befores: vec![],
            afters: vec![],
            handler: Some(Box::new(handler) as Box<Handler>)
        }
    }

    /// Link both a before and after middleware to the chain at once.
    ///
    /// Middleware that have a Before and After piece should have a constructor
    /// which returns both as a tuple, so it can be passed directly to link.
    pub fn link<B, A>(&mut self, link: (B, A))
    where A: AfterMiddleware, B: BeforeMiddleware {
        let (before, after) = link;
        self.befores.push(Box::new(before) as Box<BeforeMiddleware>);
        self.afters.push(Box::new(after) as Box<AfterMiddleware>);
    }

    /// Link a `BeforeMiddleware` to the `Chain`, after all previously linked
    /// `BeforeMiddleware`.
    pub fn link_before<B>(&mut self, before: B) where B: BeforeMiddleware {
        self.befores.push(Box::new(before) as Box<BeforeMiddleware>);
    }

    /// Link a `AfterMiddleware` to the `Chain`, after all previously linked
    /// `AfterMiddleware`.
    pub fn link_after<A>(&mut self, after: A) where A: AfterMiddleware {
        self.afters.push(Box::new(after) as Box<AfterMiddleware>);
    }

    /// Apply an `AroundMiddleware` to the `Handler` in this `Chain`.
    pub fn around<A>(&mut self, around: A) where A: AroundMiddleware {
        let mut handler = self.handler.take().unwrap();
        handler = around.around(handler);
        self.handler = Some(handler);
    }
}

impl Handler for Chain {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        // Kick off at befores, which will continue into handler
        // then afters.
        self.continue_from_before(req, 0)
    }
}

impl Chain {
    ///////////////// Implementation Helpers /////////////////

    // Enter the error flow from a before middleware, starting
    // at the passed index.
    //
    // If the index is out of bounds for the before middleware Vec,
    // this instead behaves the same as fail_from_handler.
    fn fail_from_before(&self, req: &mut Request, index: usize,
                        mut err: IronError) -> IronResult<Response> {
        // If this was the last before, yield to next phase.
        if index >= self.befores.len() {
            return self.fail_from_handler(req, err)
        }

        for (i, before) in self.befores[index..].iter().enumerate() {
            err = match before.catch(req, err) {
                Err(err) => err,
                Ok(()) => return self.continue_from_before(req, index + i + 1)
            };
        }

        // Next phase
        self.fail_from_handler(req, err)
    }

    // Enter the error flow from an errored handle, starting with the
    // first AfterMiddleware.
    fn fail_from_handler(&self, req: &mut Request,
                         err: IronError) -> IronResult<Response> {
        // Yield to next phase, nothing to do here.
        self.fail_from_after(req, 0, err)
    }

    // Enter the error flow from an errored after middleware, starting
    // with the passed index.
    //
    // If the index is out of bounds for the after middleware Vec,
    // this instead just returns the passed error.
    fn fail_from_after(&self, req: &mut Request, index: usize,
                       mut err: IronError) -> IronResult<Response> {
        // If this was the last after, we're done.
        if index == self.afters.len() { return Err(err) }

        for (i, after) in self.afters[index..].iter().enumerate() {
            err = match after.catch(req, err) {
                Err(err) => err,
                Ok(res) => return self.continue_from_after(req, index + i + 1, res)
            }
        }

        // Done
        Err(err)
    }

    // Enter the normal flow in the before middleware, starting with the passed
    // index.
    fn continue_from_before(&self, req: &mut Request,
                            index: usize) -> IronResult<Response> {
        // If this was the last beforemiddleware, start at the handler.
        if index >= self.befores.len() {
            return self.continue_from_handler(req)
        }

        for (i, before) in self.befores[index..].iter().enumerate() {
            match before.before(req) {
                Ok(()) => {},
                Err(err) => return self.fail_from_before(req, index + i + 1, err)
            }
        }

        // Yield to next phase.
        self.continue_from_handler(req)
    }

    // Enter the normal flow at the handler.
    fn continue_from_handler(&self, req: &mut Request) -> IronResult<Response> {
        // unwrap is safe because it's always Some
        match self.handler.as_ref().unwrap().handle(req) {
            Ok(res) => self.continue_from_after(req, 0, res),
            Err(err) => self.fail_from_handler(req, err)
        }
    }

    // Enter the normal flow in the after middleware, starting with the passed
    // index.
    fn continue_from_after(&self, req: &mut Request, index: usize,
                            mut res: Response) -> IronResult<Response> {
        // If this was the last after middleware, we're done.
        if index >= self.afters.len() {
            return Ok(res);
        }

        for (i, after) in self.afters[index..].iter().enumerate() {
            res = match after.after(req, res) {
                Ok(r) => r,
                Err(err) => return self.fail_from_after(req, index + i + 1, err)
            }
        }

        // We made it with no error!
        Ok(res)
    }
}

impl<F> Handler for F
where F: Send + Sync + Any + Fn(&mut Request) -> IronResult<Response> {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        (*self)(req)
    }
}

impl Handler for Box<Handler> {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        (**self).handle(req)
    }
}

impl<F> BeforeMiddleware for F
where F: Send + Sync + Any + Fn(&mut Request) -> IronResult<()> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        (*self)(req)
    }
}

impl BeforeMiddleware for Box<BeforeMiddleware> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        (**self).before(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<()> {
        (**self).catch(req, err)
    }
}

impl<F> AfterMiddleware for F
where F: Send + Sync + Any + Fn(&mut Request, Response) -> IronResult<Response> {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        (*self)(req, res)
    }
}

impl AfterMiddleware for Box<AfterMiddleware> {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        (**self).after(req, res)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
        (**self).catch(req, err)
    }
}

impl<F> AroundMiddleware for F
where F: FnOnce(Box<Handler>) -> Box<Handler> {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        self(handler)
    }
}

#[cfg(test)]
mod test;

<commit_msg>(feat) allow Arc wrapped middleware<commit_after>//! Iron's Middleware and Handler System
//!
//! Iron's Middleware system is best modeled with a diagram.
//!
//! ```plain
//! [b] = BeforeMiddleware
//! [a] = AfterMiddleware
//! [[h]] = AroundMiddleware
//! [h] = Handler
//! ```
//!
//! With no errors, the flow looks like:
//!
//! ```plain
//! [b] -> [b] -> [b] -> [[[[h]]]] -> [a] -> [a] -> [a] -> [a]
//! ```
//!
//! A request first travels through all BeforeMiddleware, then a Response is generated
//! by the Handler, which can be an arbitrary nesting of AroundMiddleware, then all
//! AfterMiddleware are called with both the Request and Response. After all AfterMiddleware
//! have been fired, the response is written back to the client.
//!
//! Iron's error handling system is pragmatic and focuses on tracking two pieces
//! of information for error receivers (other middleware):
//!
//! * The cause of the error
//! * The result (what to do about) the error.
//!
//! The cause of the error is represented simply by the error itself, and the result
//! of the error, representing the action to take in response to the error, is a complete
//! Response, which will be sent at the end of the error flow.
//!
//! When an error is thrown in Iron by any middleware or handler returning an `Err`
//! variant with an `IronError`, the flow of the Request switches to the error flow,
//! which proceeds to just call the `catch` method of middleware and sidesteps the
//! `Handler` entirely, since there is already a Response in the error.
//!
//! A Request can exit the error flow by returning an Ok from any of the catch methods.
//! This resumes the flow at the middleware immediately following the middleware which
//! handled the error. It is impossible to "go back" to an earlier middleware that was
//! skipped.
//!
//! Generally speaking, returning a 5XX error code means that the error flow should be
//! entered by raising an explicit error. Dealing with 4XX errors is trickier, since
//! the server may not want to recognize an error that is entirely the clients fault;
//! handling of 4XX error codes is up to to each application and middleware author.
//!
//! Middleware authors should be cognizant that their middleware may be skipped during
//! the error flow. Anything that *must* be done to each Request or Response should
//! be run during both the normal and error flow by implementing the `catch` method to
//! also do the necessary action.
//!

use std::any::Any;
use std::sync::Arc;
use {Request, Response, IronResult, IronError};

/// `Handler`s are responsible for handling requests by creating Responses from Requests.
pub trait Handler: Send + Sync + Any {
    /// Produce a `Response` from a Request, with the possibility of error.
    fn handle(&self, &mut Request) -> IronResult<Response>;
}

/// `BeforeMiddleware` are fired before a `Handler` is called inside of a Chain.
///
/// `BeforeMiddleware` are responsible for doing request pre-processing that requires
/// the ability to change control-flow, such as authorization middleware, or for editing
/// the request by modifying the headers.
///
/// `BeforeMiddleware` only have access to the Request, if you need to modify or read
/// a Response, you will need `AfterMiddleware`. Middleware which wishes to send an
/// early response that is not an error cannot be `BeforeMiddleware`, but should
/// instead be `AroundMiddleware`.
pub trait BeforeMiddleware: Send + Sync + Any {
    /// Do whatever work this middleware should do with a `Request` object.
    fn before(&self, _: &mut Request) -> IronResult<()> { Ok(()) }

    /// Respond to an error thrown by a previous `BeforeMiddleware`.
    ///
    /// Returning a `Ok` will cause the request to resume the normal flow at the
    /// next `BeforeMiddleware`, or if this was the last `BeforeMiddleware`,
    /// at the `Handler`.
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<()> { Err(err) }
}

/// `AfterMiddleware` are fired after a `Handler` is called inside of a Chain.
///
/// `AfterMiddleware` receive both a `Request` and a `Response` and are responsible for doing
/// any response post-processing.
///
/// `AfterMiddleware` should *not* overwrite the contents of a Response. In
/// the common case, a complete response is generated by the Chain's `Handler` and
/// `AfterMiddleware` simply do post-processing of that Response, such as
/// adding headers or logging.
pub trait AfterMiddleware: Send + Sync + Any {
    /// Do whatever post-processing this middleware should do.
    fn after(&self, _: &mut Request, res: Response) -> IronResult<Response> {
        Ok(res)
    }

    /// Respond to an error thrown by previous `AfterMiddleware`, the `Handler`,
    /// or a `BeforeMiddleware`.
    ///
    /// Returning `Ok` will cause the request to resume the normal flow at the
    /// next `AfterMiddleware`.
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        Err(err)
    }
}

/// AroundMiddleware are used to wrap and replace the `Handler` in a `Chain`.
///
/// AroundMiddleware produce `Handler`s through their `around` method, which is
/// called once on insertion into a Chain or can be called manually outside of a
/// `Chain`.
pub trait AroundMiddleware {
    /// Produce a `Handler` from this `AroundMiddleware` given another `Handler`.
    ///
    /// Usually this means wrapping the handler and editing the `Request` on the
    /// way in and the `Response` on the way out.
    ///
    /// This is called only once, when an `AroundMiddleware` is added to a `Chain`
    /// using `Chain::around`, it is passed the `Chain`'s current `Handler`.
    fn around(self, handler: Box<Handler>) -> Box<Handler>;
}

/// The middleware chain used in Iron.
///
/// This is a canonical implementation of Iron's middleware system,
/// but Iron's infrastructure is flexible enough to allow alternate
/// systems.
pub struct Chain {
    befores: Vec<Box<BeforeMiddleware>>,
    afters: Vec<Box<AfterMiddleware>>,

    // Internal invariant: this is always Some
    handler: Option<Box<Handler>>
}

impl Chain {
    /// Construct a new ChainBuilder from a `Handler`.
    pub fn new<H: Handler>(handler: H) -> Chain {
        Chain {
            befores: vec![],
            afters: vec![],
            handler: Some(Box::new(handler) as Box<Handler>)
        }
    }

    /// Link both a before and after middleware to the chain at once.
    ///
    /// Middleware that have a Before and After piece should have a constructor
    /// which returns both as a tuple, so it can be passed directly to link.
    pub fn link<B, A>(&mut self, link: (B, A))
    where A: AfterMiddleware, B: BeforeMiddleware {
        let (before, after) = link;
        self.befores.push(Box::new(before) as Box<BeforeMiddleware>);
        self.afters.push(Box::new(after) as Box<AfterMiddleware>);
    }

    /// Link a `BeforeMiddleware` to the `Chain`, after all previously linked
    /// `BeforeMiddleware`.
    pub fn link_before<B>(&mut self, before: B) where B: BeforeMiddleware {
        self.befores.push(Box::new(before) as Box<BeforeMiddleware>);
    }

    /// Link a `AfterMiddleware` to the `Chain`, after all previously linked
    /// `AfterMiddleware`.
    pub fn link_after<A>(&mut self, after: A) where A: AfterMiddleware {
        self.afters.push(Box::new(after) as Box<AfterMiddleware>);
    }

    /// Apply an `AroundMiddleware` to the `Handler` in this `Chain`.
    pub fn around<A>(&mut self, around: A) where A: AroundMiddleware {
        let mut handler = self.handler.take().unwrap();
        handler = around.around(handler);
        self.handler = Some(handler);
    }
}

impl Handler for Chain {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        // Kick off at befores, which will continue into handler
        // then afters.
        self.continue_from_before(req, 0)
    }
}

impl Chain {
    ///////////////// Implementation Helpers /////////////////

    // Enter the error flow from a before middleware, starting
    // at the passed index.
    //
    // If the index is out of bounds for the before middleware Vec,
    // this instead behaves the same as fail_from_handler.
    fn fail_from_before(&self, req: &mut Request, index: usize,
                        mut err: IronError) -> IronResult<Response> {
        // If this was the last before, yield to next phase.
        if index >= self.befores.len() {
            return self.fail_from_handler(req, err)
        }

        for (i, before) in self.befores[index..].iter().enumerate() {
            err = match before.catch(req, err) {
                Err(err) => err,
                Ok(()) => return self.continue_from_before(req, index + i + 1)
            };
        }

        // Next phase
        self.fail_from_handler(req, err)
    }

    // Enter the error flow from an errored handle, starting with the
    // first AfterMiddleware.
    fn fail_from_handler(&self, req: &mut Request,
                         err: IronError) -> IronResult<Response> {
        // Yield to next phase, nothing to do here.
        self.fail_from_after(req, 0, err)
    }

    // Enter the error flow from an errored after middleware, starting
    // with the passed index.
    //
    // If the index is out of bounds for the after middleware Vec,
    // this instead just returns the passed error.
    fn fail_from_after(&self, req: &mut Request, index: usize,
                       mut err: IronError) -> IronResult<Response> {
        // If this was the last after, we're done.
        if index == self.afters.len() { return Err(err) }

        for (i, after) in self.afters[index..].iter().enumerate() {
            err = match after.catch(req, err) {
                Err(err) => err,
                Ok(res) => return self.continue_from_after(req, index + i + 1, res)
            }
        }

        // Done
        Err(err)
    }

    // Enter the normal flow in the before middleware, starting with the passed
    // index.
    fn continue_from_before(&self, req: &mut Request,
                            index: usize) -> IronResult<Response> {
        // If this was the last beforemiddleware, start at the handler.
        if index >= self.befores.len() {
            return self.continue_from_handler(req)
        }

        for (i, before) in self.befores[index..].iter().enumerate() {
            match before.before(req) {
                Ok(()) => {},
                Err(err) => return self.fail_from_before(req, index + i + 1, err)
            }
        }

        // Yield to next phase.
        self.continue_from_handler(req)
    }

    // Enter the normal flow at the handler.
    fn continue_from_handler(&self, req: &mut Request) -> IronResult<Response> {
        // unwrap is safe because it's always Some
        match self.handler.as_ref().unwrap().handle(req) {
            Ok(res) => self.continue_from_after(req, 0, res),
            Err(err) => self.fail_from_handler(req, err)
        }
    }

    // Enter the normal flow in the after middleware, starting with the passed
    // index.
    fn continue_from_after(&self, req: &mut Request, index: usize,
                            mut res: Response) -> IronResult<Response> {
        // If this was the last after middleware, we're done.
        if index >= self.afters.len() {
            return Ok(res);
        }

        for (i, after) in self.afters[index..].iter().enumerate() {
            res = match after.after(req, res) {
                Ok(r) => r,
                Err(err) => return self.fail_from_after(req, index + i + 1, err)
            }
        }

        // We made it with no error!
        Ok(res)
    }
}

impl<F> Handler for F
where F: Send + Sync + Any + Fn(&mut Request) -> IronResult<Response> {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        (*self)(req)
    }
}

impl Handler for Box<Handler> {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        (**self).handle(req)
    }
}

impl<F> BeforeMiddleware for F
where F: Send + Sync + Any + Fn(&mut Request) -> IronResult<()> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        (*self)(req)
    }
}

impl BeforeMiddleware for Box<BeforeMiddleware> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        (**self).before(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<()> {
        (**self).catch(req, err)
    }
}

impl<T> BeforeMiddleware for Arc<T> where T: BeforeMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        (**self).before(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<()> {
        (**self).catch(req, err)
    }
}

impl<F> AfterMiddleware for F
where F: Send + Sync + Any + Fn(&mut Request, Response) -> IronResult<Response> {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        (*self)(req, res)
    }
}

impl AfterMiddleware for Box<AfterMiddleware> {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        (**self).after(req, res)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
        (**self).catch(req, err)
    }
}

impl<T> AfterMiddleware for Arc<T> where T: AfterMiddleware {
    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
        (**self).after(req, res)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
        (**self).catch(req, err)
    }
}

impl<F> AroundMiddleware for F
where F: FnOnce(Box<Handler>) -> Box<Handler> {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        self(handler)
    }
}

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>//! Defines the `MoveGenerator` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use board::*;
use moves::*;
use value::*;
use evaluator::Evaluator;
use utils::bitsets::*;
use utils::BoardGeometry;

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position and can:
///
/// * Generate all legal moves, or a subset of all legal moves in the
///   current position.
///
/// * Perform static exchange evaluation for the generated moves.
///
/// * Play a selected move and take it back.
///
/// * Provide a static evaluator bound to the current position.
///
/// * Calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method will be relatively slow if the
    /// implementation calculates the hash value "from
    /// scratch". Inspect the implementation before using `hash` in
    /// time-critical paths. (See `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_all`, `generate_forcing`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < PIECE_NONE);
        debug_assert!(m.captured_piece() <= PIECE_NONE);
        const PIECE_VALUES: [Value; 8] = [10000, 975, 500, 325, 325, 100, 0, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        unsafe {
            let geometry = BoardGeometry::get();
            let behind_blocker: &[Bitboard; 64] = geometry.squares_behind_blocker
                                                          .get_unchecked(exchange_square);
            let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
            let color: &[Bitboard; 2] = &self.board().pieces.color;
            let occupied = self.board().occupied;
            let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
            let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

            // `may_xray` holds the set of pieces that may block attacks
            // from other pieces. We will consider adding new
            // attackers/defenders every time a piece from the `may_xray`
            // set makes a capture.
            let may_xray = piece_type[PAWN] | piece_type[BISHOP] | piece_type[ROOK] |
                           piece_type[QUEEN];

            // These variables will be updated on each capture:
            let mut us = self.board().to_move;
            let mut depth = 0;
            let mut piece;
            let mut orig_square_bb = 1 << m.orig_square();
            let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                              self.attacks_to(BLACK, exchange_square);

            // The `gain` array will hold the total material gained at
            // each `depth`, from the viewpoint of the side that made the
            // last capture (`us`).
            let mut gain: [Value; 34] = uninitialized();
            gain[0] = if m.move_type() == MOVE_PROMOTION {
                piece = Move::piece_from_aux_data(m.aux_data());
                PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
            } else {
                piece = m.played_piece();
                *PIECE_VALUES.get_unchecked(m.captured_piece())
            };

            // Examine the possible exchanges, fill the `gain` array.
            'exchange: while orig_square_bb != 0 {
                let current_gain = *gain.get_unchecked(depth);

                // Store a speculative value that will be used if the
                // captured piece happens to be defended.
                let speculative_gain: &mut Value = gain.get_unchecked_mut(depth + 1);
                *speculative_gain = *PIECE_VALUES.get_unchecked(piece) - current_gain;

                if max(-current_gain, *speculative_gain) < 0 {
                    // The side that made the last capture wins even if
                    // the captured piece happens to be defended. So, we
                    // stop here to save precious CPU cycles. Note that
                    // here we may happen to return an incorrect SEE
                    // value, but the sign will be correct, which is by
                    // far the most important information.
                    break;
                }

                // Register that `orig_square_bb` is now vacant.
                attackers_and_defenders &= !orig_square_bb;

                // Consider adding new attackers/defenders, now that
                // `orig_square_bb` is vacant.
                if orig_square_bb & may_xray != 0 {
                    attackers_and_defenders |= {
                        let behind = occupied &
                                     *behind_blocker.get_unchecked(bitscan_forward(orig_square_bb));
                        match behind & straight_sliders &
                              geometry.attacks_from_unsafe(ROOK, exchange_square, behind) {
                            0 => {
                                // Not a straight slider -- possibly a diagonal slider.
                                behind & diag_sliders &
                                geometry.attacks_from_unsafe(BISHOP, exchange_square, behind)
                            }
                            x => x,
                        }
                    };
                }

                // Change the side to move.
                us ^= 1;

                // Find the next piece to enter the exchange. (The least
                // valuable piece belonging to the side to move.)
                let candidates = attackers_and_defenders & *color.get_unchecked(us);
                if candidates != 0 {
                    for p in (KING..PIECE_NONE).rev() {
                        let bb = candidates & piece_type[p];
                        if bb != 0 {
                            depth += 1;
                            piece = p;
                            orig_square_bb = ls1b(bb);
                            continue 'exchange;
                        }
                    }
                }
                break 'exchange;
            }

            // Negamax the `gain` array for the final static exchange
            // evaluation. (The `gain` array actually represents an unary
            // tree, at each node of which the player can either continue
            // the exchange or back off.)
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
            gain[0]
        }
    }
}
<commit_msg>optimize evaluate_move()<commit_after>//! Defines the `MoveGenerator` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use board::*;
use moves::*;
use value::*;
use evaluator::Evaluator;
use utils::bitsets::*;
use utils::BoardGeometry;

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position and can:
///
/// * Generate all legal moves, or a subset of all legal moves in the
///   current position.
///
/// * Perform static exchange evaluation for the generated moves.
///
/// * Play a selected move and take it back.
///
/// * Provide a static evaluator bound to the current position.
///
/// * Calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method will be relatively slow if the
    /// implementation calculates the hash value "from
    /// scratch". Inspect the implementation before using `hash` in
    /// time-critical paths. (See `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_all`, `generate_forcing`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < PIECE_NONE);
        debug_assert!(m.captured_piece() <= PIECE_NONE);
        const PIECE_VALUES: [Value; 8] = [10000, 975, 500, 325, 325, 100, 0, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        unsafe {
            let geometry = BoardGeometry::get();
            let behind_blocker: &[Bitboard; 64] = geometry.squares_behind_blocker
                                                          .get_unchecked(exchange_square);
            let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
            let color: &[Bitboard; 2] = &self.board().pieces.color;
            let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
            let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

            // `may_xray` holds the set of pieces that may block attacks
            // from other pieces. We will consider adding new
            // attackers/defenders every time a piece from the `may_xray`
            // set makes a capture.
            //
            // TODO: This is probably not necessary if `bitscan_1bit`
            // is translated to 1 instruction. Otherwise, it probably
            // saves few CPU cycles.
            let may_xray = piece_type[PAWN] | straight_sliders | diag_sliders;

            // These variables will be updated on each capture:
            let mut us = self.board().to_move;
            let mut depth = 0;
            let mut piece;
            let mut orig_square_bb = 1 << m.orig_square();
            let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                              self.attacks_to(BLACK, exchange_square);

            // The `gain` array will hold the total material gained at
            // each `depth`, from the viewpoint of the side that made the
            // last capture (`us`).
            let mut gain: [Value; 34] = uninitialized();
            gain[0] = if m.move_type() == MOVE_PROMOTION {
                piece = Move::piece_from_aux_data(m.aux_data());
                PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
            } else {
                piece = m.played_piece();
                *PIECE_VALUES.get_unchecked(m.captured_piece())
            };

            // Examine the possible exchanges, fill the `gain` array.
            'exchange: while orig_square_bb != 0 {
                let current_gain = *gain.get_unchecked(depth);

                // Store a speculative value that will be used if the
                // captured piece happens to be defended.
                let speculative_gain: &mut Value = gain.get_unchecked_mut(depth + 1);
                *speculative_gain = *PIECE_VALUES.get_unchecked(piece) - current_gain;

                if max(-current_gain, *speculative_gain) < 0 {
                    // The side that made the last capture wins even if
                    // the captured piece happens to be defended. So, we
                    // stop here to save precious CPU cycles. Note that
                    // here we may happen to return an incorrect SEE
                    // value, but the sign will be correct, which is by
                    // far the most important information.
                    break;
                }

                // Register that capturing piece's origin square is now vacant.
                attackers_and_defenders &= !orig_square_bb;

                // Consider adding new attackers/defenders, now that
                // capturing piece's origin square is vacant.
                if orig_square_bb & may_xray != 0 {
                    let behind = self.board().occupied &
                                 *behind_blocker.get_unchecked(bitscan_1bit(orig_square_bb));
                    if behind & (straight_sliders | diag_sliders) != 0 {
                        attackers_and_defenders |=
                            match behind & straight_sliders &
                                  geometry.attacks_from_unsafe(ROOK, exchange_square, behind) {
                                0 => {
                                    // Not a straight slider, possibly a diagonal slider.
                                    behind & diag_sliders &
                                    geometry.attacks_from_unsafe(BISHOP, exchange_square, behind)
                                }
                                bb => {
                                    // A straight slider.
                                    bb
                                }
                            };
                    }
                }

                // Change the side to move.
                us ^= 1;

                // Find the next piece to enter the exchange. (The least
                // valuable piece belonging to the side to move.)
                let candidates = attackers_and_defenders & *color.get_unchecked(us);
                if candidates != 0 {
                    for p in (KING..PIECE_NONE).rev() {
                        let bb = candidates & piece_type[p];
                        if bb != 0 {
                            depth += 1;
                            piece = p;
                            orig_square_bb = ls1b(bb);
                            continue 'exchange;
                        }
                    }
                }
                break 'exchange;
            }

            // Negamax the `gain` array for the final static exchange
            // evaluation. (The `gain` array actually represents an unary
            // tree, at each node of which the player can either continue
            // the exchange or back off.)
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
            gain[0]
        }
    }
}
<|endoftext|>