<commit_before>use codec::{
    eyre::{bail, Result},
    stencila_schema::Node,
    Codec, CodecTrait,
};
use codec_format::FormatCodec;
use formats::{match_name, Format};
use once_cell::sync::Lazy;
use std::{collections::BTreeMap, path::Path, sync::Arc};

// Re-exports for use in other crates that call the following functions
pub use codec::{DecodeOptions, EncodeOptions};

// The following high level functions hide the implementation
// detail of having a static list of codecs. They are intended as the
// only public interface for this crate.

/// Decode a document node from a string
pub async fn from_str(content: &str, format: &str, options: Option<DecodeOptions>) -> Result<Node> {
    CODECS.from_str(content, format, options).await
}

/// Decode a document node from a file system path
pub async fn from_path(path: &Path, format: &str, options: Option<DecodeOptions>) -> Result<Node> {
    CODECS.from_path(path, format, options).await
}

/// Encode a document node to a string
pub async fn to_string(
    node: &Node,
    format: &str,
    options: Option<EncodeOptions>,
) -> Result<String> {
    CODECS.to_string(node, format, options).await
}

/// Encode a document node to a file system path
pub async fn to_path(
    node: &Node,
    path: &Path,
    format: &str,
    options: Option<EncodeOptions>,
) -> Result<()> {
    CODECS.to_path(node, path, format, options).await
}

/// The set of registered codecs in the current process
static CODECS: Lazy<Arc<Codecs>> = Lazy::new(|| Arc::new(Codecs::new()));

/// A set of registered codecs, either built-in, or provided by plugins
struct Codecs {
    inner: BTreeMap<String, Codec>,
}

/// A macro to dispatch methods to builtin codecs
///
/// This avoids having to do a search over the codecs's specs for matching
/// `formats`.
macro_rules! dispatch_builtins {
    ($format:expr, $method:ident $(,$arg:expr)*) => {
        match $format {
            #[cfg(feature = "codec-date")]
            Format::Date => Some(codec_date::DateCodec::$method($($arg),*)),
            #[cfg(feature = "codec-docx")]
            Format::Docx => Some(codec_docx::DocxCodec::$method($($arg),*)),
            #[cfg(feature = "codec-html")]
            Format::Html => Some(codec_html::HtmlCodec::$method($($arg),*)),
            #[cfg(feature = "codec-ipynb")]
            Format::Ipynb => Some(codec_ipynb::IpynbCodec::$method($($arg),*)),
            #[cfg(feature = "codec-json")]
            Format::Json => Some(codec_json::JsonCodec::$method($($arg),*)),
            #[cfg(feature = "codec-json5")]
            Format::Json5 => Some(codec_json5::Json5Codec::$method($($arg),*)),
            #[cfg(feature = "codec-latex")]
            Format::LaTeX => Some(codec_latex::LatexCodec::$method($($arg),*)),
            #[cfg(feature = "codec-md")]
            Format::Markdown => Some(codec_md::MdCodec::$method($($arg),*)),
            #[cfg(feature = "codec-pandoc")]
            Format::Pandoc => Some(codec_pandoc::PandocCodec::$method($($arg),*)),
            #[cfg(feature = "codec-pdf")]
            Format::Pdf => Some(codec_pdf::PdfCodec::$method($($arg),*)),
            #[cfg(feature = "codec-person")]
            Format::Person => Some(codec_person::PersonCodec::$method($($arg),*)),
            #[cfg(feature = "codec-png")]
            Format::Png => Some(codec_png::PngCodec::$method($($arg),*)),
            #[cfg(feature = "codec-rmd")]
            Format::RMarkdown => Some(codec_rmd::RmdCodec::$method($($arg),*)),
            #[cfg(feature = "codec-rpng")]
            Format::Rpng => Some(codec_rpng::RpngCodec::$method($($arg),*)),
            #[cfg(feature = "codec-toml")]
            Format::Toml => Some(codec_toml::TomlCodec::$method($($arg),*)),
            #[cfg(feature = "codec-txt")]
            Format::PlainText => Some(codec_txt::TxtCodec::$method($($arg),*)),
            #[cfg(feature = "codec-yaml")]
            Format::Yaml => Some(codec_yaml::YamlCodec::$method($($arg),*)),

            _ => None
        }
    };
}

impl Codecs {
    /// Create a new codec registry
    ///
    /// Note that these strings are labels for the codec which
    /// aim to be consistent with the codec name, are convenient
    /// to use to `stencila codecs show`, and don't need to be
    /// consistent with format names or aliases.
    pub fn new() -> Self {
        let inner = vec![
            #[cfg(feature = "codec-date")]
            ("date", codec_date::DateCodec::spec()),
            #[cfg(feature = "codec-docx")]
            ("docx", codec_docx::DocxCodec::spec()),
            #[cfg(feature = "codec-html")]
            ("html", codec_html::HtmlCodec::spec()),
            #[cfg(feature = "codec-ipynb")]
            ("ipynb", codec_ipynb::IpynbCodec::spec()),
            #[cfg(feature = "codec-json")]
            ("json", codec_json::JsonCodec::spec()),
            #[cfg(feature = "codec-json5")]
            ("json5", codec_json5::Json5Codec::spec()),
            #[cfg(feature = "codec-latex")]
            ("latex", codec_latex::LatexCodec::spec()),
            #[cfg(feature = "codec-md")]
            ("md", codec_md::MdCodec::spec()),
            #[cfg(feature = "codec-pandoc")]
            ("pandoc", codec_pandoc::PandocCodec::spec()),
            #[cfg(feature = "codec-pdf")]
            ("pdf", codec_pdf::PdfCodec::spec()),
            #[cfg(feature = "codec-person")]
            ("person", codec_person::PersonCodec::spec()),
            #[cfg(feature = "codec-png")]
            ("png", codec_png::PngCodec::spec()),
            #[cfg(feature = "codec-rmd")]
            ("rmd", codec_rmd::RmdCodec::spec()),
            #[cfg(feature = "codec-rpng")]
            ("rpng", codec_rpng::RpngCodec::spec()),
            #[cfg(feature = "codec-toml")]
            ("toml", codec_toml::TomlCodec::spec()),
            #[cfg(feature = "codec-txt")]
            ("txt", codec_txt::TxtCodec::spec()),
            #[cfg(feature = "codec-yaml")]
            ("yaml", codec_yaml::YamlCodec::spec()),
        ]
        .into_iter()
        .map(|(label, codec)| (label.to_string(), codec))
        .collect();

        Self { inner }
    }

    /// List all the codecs
    fn list(&self) -> Vec<String> {
        self.inner
            .keys()
            .into_iter()
            .cloned()
            .collect::<Vec<String>>()
    }

    /// Get the codec with the given id
    fn get(&self, label: &str) -> Result<Codec> {
        match self.inner.get(label) {
            Some(codec) => Ok(codec.clone()),
            None => bail!("No codec with label `{}`", label),
        }
    }

    /// Decode a document node from a string
    #[allow(clippy::needless_update)]
    async fn from_str(
        &self,
        content: &str,
        format: &str,
        options: Option<DecodeOptions>,
    ) -> Result<Node> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(DecodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, from_str_async, content, options.clone()) {
            return future.await;
        }

        if let Ok(node) = FormatCodec::from_str_async(content, options).await {
            return Ok(node);
        }

        bail!(
            "Unable to decode from string with format `{}`: no matching codec found",
            format_spec.title
        )
    }

    /// Decode a document node from a file system path
    #[allow(clippy::needless_update)]
    async fn from_path(
        &self,
        path: &Path,
        format: &str,
        options: Option<DecodeOptions>,
    ) -> Result<Node> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(DecodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, from_path, path, options) {
            return future.await;
        }

        bail!(
            "Unable to decode from path with format `{}`: no matching codec found",
            format_spec.title
        )
    }

    /// Encode a document node to a string
    #[allow(unused_variables)]
    async fn to_string(
        &self,
        node: &Node,
        format: &str,
        options: Option<EncodeOptions>,
    ) -> Result<String> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(EncodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, to_string_async, node, options) {
            return future.await;
        }

        bail!(
            "Unable to encode to string of format `{}`: no matching codec found",
            format_spec.title
        )
    }

    /// Encode a document node to a file system path
    async fn to_path(
        &self,
        node: &Node,
        path: &Path,
        format: &str,
        options: Option<EncodeOptions>,
    ) -> Result<()> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(EncodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, to_path, node, path, options) {
            return future.await;
        }

        bail!(
            "Unable to encode to path with format `{}`: no matching codec found",
            format_spec.title
        )
    }
}

impl Default for Codecs {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(feature = "cli")]
pub mod commands {
    use super::*;
    use cli_utils::{result, Result, Run};
    use codec::async_trait::async_trait;
    use structopt::StructOpt;

    /// Manage codecs
    ///
    /// In Stencila, a "codec" is responsible for converting documents
    /// to ("encoding") and from ("decoding") a format (e.g. Markdown).
    /// This command alls you to list the available codecs and see their
    /// specifications (e.g. which formats they support).
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Command {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        List(List),
        Show(Show),
    }

    #[async_trait]
    impl Run for Command {
        async fn run(&self) -> Result {
            let Self { action } = self;
            match action {
                Action::List(action) => action.run().await,
                Action::Show(action) => action.run().await,
            }
        }
    }

    /// List the codecs available
    ///
    /// The list of available codecs includes those that are built into the Stencila
    /// binary (e.g. `html`) as well as any codecs provided by plugins.
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct List {}

    #[async_trait]
    impl Run for List {
        async fn run(&self) -> Result {
            let list = CODECS.list();
            result::value(list)
        }
    }

    /// Show the specifications of a codec
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Show {
        /// The label of the codec
        ///
        /// To get the list of codec labels use `stencila codecs list`.
        label: String,
    }

    #[async_trait]
    impl Run for Show {
        async fn run(&self) -> Result {
            let codec = CODECS.get(&self.label)?;
            result::value(codec)
        }
    }
}
<commit_msg>feat(Codecs CLI): Generate a Markdown table for `list` command<commit_after>use codec::{
    eyre::{bail, Result},
    stencila_schema::Node,
    Codec, CodecTrait,
};
use codec_format::FormatCodec;
use formats::{match_name, Format};
use once_cell::sync::Lazy;
use std::{collections::BTreeMap, path::Path, sync::Arc};

// Re-exports for use in other crates that call the following functions
pub use codec::{DecodeOptions, EncodeOptions};

// The following high level functions hide the implementation
// detail of having a static list of codecs. They are intended as the
// only public interface for this crate.

/// Decode a document node from a string
pub async fn from_str(content: &str, format: &str, options: Option<DecodeOptions>) -> Result<Node> {
    CODECS.from_str(content, format, options).await
}

/// Decode a document node from a file system path
pub async fn from_path(path: &Path, format: &str, options: Option<DecodeOptions>) -> Result<Node> {
    CODECS.from_path(path, format, options).await
}

/// Encode a document node to a string
pub async fn to_string(
    node: &Node,
    format: &str,
    options: Option<EncodeOptions>,
) -> Result<String> {
    CODECS.to_string(node, format, options).await
}

/// Encode a document node to a file system path
pub async fn to_path(
    node: &Node,
    path: &Path,
    format: &str,
    options: Option<EncodeOptions>,
) -> Result<()> {
    CODECS.to_path(node, path, format, options).await
}

/// The set of registered codecs in the current process
static CODECS: Lazy<Arc<Codecs>> = Lazy::new(|| Arc::new(Codecs::new()));

/// A set of registered codecs, either built-in, or provided by plugins
struct Codecs {
    inner: BTreeMap<String, Codec>,
}

/// A macro to dispatch methods to builtin codecs
///
/// This avoids having to do a search over the codecs's specs for matching
/// `formats`.
macro_rules! dispatch_builtins {
    ($format:expr, $method:ident $(,$arg:expr)*) => {
        match $format {
            #[cfg(feature = "codec-date")]
            Format::Date => Some(codec_date::DateCodec::$method($($arg),*)),
            #[cfg(feature = "codec-docx")]
            Format::Docx => Some(codec_docx::DocxCodec::$method($($arg),*)),
            #[cfg(feature = "codec-html")]
            Format::Html => Some(codec_html::HtmlCodec::$method($($arg),*)),
            #[cfg(feature = "codec-ipynb")]
            Format::Ipynb => Some(codec_ipynb::IpynbCodec::$method($($arg),*)),
            #[cfg(feature = "codec-json")]
            Format::Json => Some(codec_json::JsonCodec::$method($($arg),*)),
            #[cfg(feature = "codec-json5")]
            Format::Json5 => Some(codec_json5::Json5Codec::$method($($arg),*)),
            #[cfg(feature = "codec-latex")]
            Format::LaTeX => Some(codec_latex::LatexCodec::$method($($arg),*)),
            #[cfg(feature = "codec-md")]
            Format::Markdown => Some(codec_md::MdCodec::$method($($arg),*)),
            #[cfg(feature = "codec-pandoc")]
            Format::Pandoc => Some(codec_pandoc::PandocCodec::$method($($arg),*)),
            #[cfg(feature = "codec-pdf")]
            Format::Pdf => Some(codec_pdf::PdfCodec::$method($($arg),*)),
            #[cfg(feature = "codec-person")]
            Format::Person => Some(codec_person::PersonCodec::$method($($arg),*)),
            #[cfg(feature = "codec-png")]
            Format::Png => Some(codec_png::PngCodec::$method($($arg),*)),
            #[cfg(feature = "codec-rmd")]
            Format::RMarkdown => Some(codec_rmd::RmdCodec::$method($($arg),*)),
            #[cfg(feature = "codec-rpng")]
            Format::Rpng => Some(codec_rpng::RpngCodec::$method($($arg),*)),
            #[cfg(feature = "codec-toml")]
            Format::Toml => Some(codec_toml::TomlCodec::$method($($arg),*)),
            #[cfg(feature = "codec-txt")]
            Format::PlainText => Some(codec_txt::TxtCodec::$method($($arg),*)),
            #[cfg(feature = "codec-yaml")]
            Format::Yaml => Some(codec_yaml::YamlCodec::$method($($arg),*)),

            _ => None
        }
    };
}

impl Codecs {
    /// Create a new codec registry
    ///
    /// Note that these strings are labels for the codec which
    /// aim to be consistent with the codec name, are convenient
    /// to use to `stencila codecs show`, and don't need to be
    /// consistent with format names or aliases.
    pub fn new() -> Self {
        let inner = vec![
            #[cfg(feature = "codec-date")]
            ("date", codec_date::DateCodec::spec()),
            #[cfg(feature = "codec-docx")]
            ("docx", codec_docx::DocxCodec::spec()),
            #[cfg(feature = "codec-html")]
            ("html", codec_html::HtmlCodec::spec()),
            #[cfg(feature = "codec-ipynb")]
            ("ipynb", codec_ipynb::IpynbCodec::spec()),
            #[cfg(feature = "codec-json")]
            ("json", codec_json::JsonCodec::spec()),
            #[cfg(feature = "codec-json5")]
            ("json5", codec_json5::Json5Codec::spec()),
            #[cfg(feature = "codec-latex")]
            ("latex", codec_latex::LatexCodec::spec()),
            #[cfg(feature = "codec-md")]
            ("md", codec_md::MdCodec::spec()),
            #[cfg(feature = "codec-pandoc")]
            ("pandoc", codec_pandoc::PandocCodec::spec()),
            #[cfg(feature = "codec-pdf")]
            ("pdf", codec_pdf::PdfCodec::spec()),
            #[cfg(feature = "codec-person")]
            ("person", codec_person::PersonCodec::spec()),
            #[cfg(feature = "codec-png")]
            ("png", codec_png::PngCodec::spec()),
            #[cfg(feature = "codec-rmd")]
            ("rmd", codec_rmd::RmdCodec::spec()),
            #[cfg(feature = "codec-rpng")]
            ("rpng", codec_rpng::RpngCodec::spec()),
            #[cfg(feature = "codec-toml")]
            ("toml", codec_toml::TomlCodec::spec()),
            #[cfg(feature = "codec-txt")]
            ("txt", codec_txt::TxtCodec::spec()),
            #[cfg(feature = "codec-yaml")]
            ("yaml", codec_yaml::YamlCodec::spec()),
        ]
        .into_iter()
        .map(|(label, codec)| (label.to_string(), codec))
        .collect();

        Self { inner }
    }

    /// List the available codecs
    fn list(&self) -> &BTreeMap<String, Codec> {
        &self.inner
    }

    /// Generate a Markdown table of the available codecs
    fn table(&self) -> String {
        let cols = "|-----|------|-------|----------|-------------------|";
        let head = "|Label|Status|Formats|Root types|Unsupported content";
        let body = self
            .inner
            .iter()
            .map(|(label, codec)| {
                format!(
                    "|{}|{}|{}|{}|{}|",
                    label,
                    codec.status,
                    codec.formats.join(", "),
                    if codec.root_types == vec!["*"] {
                        "*all*".to_string()
                    } else {
                        codec.root_types.join(", ")
                    },
                    codec.unsupported_types.join(", ")
                )
            })
            .collect::<Vec<String>>()
            .join("\n");
        format!(
            "{top}\n{head}\n{align}\n{body}\n{bottom}\n",
            top = cols,
            head = head,
            align = cols,
            body = body,
            bottom = cols
        )
    }

    /// Get the codec with the given id
    fn get(&self, label: &str) -> Result<Codec> {
        match self.inner.get(label) {
            Some(codec) => Ok(codec.clone()),
            None => bail!("No codec with label `{}`", label),
        }
    }

    /// Decode a document node from a string
    #[allow(clippy::needless_update)]
    async fn from_str(
        &self,
        content: &str,
        format: &str,
        options: Option<DecodeOptions>,
    ) -> Result<Node> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(DecodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, from_str_async, content, options.clone()) {
            return future.await;
        }

        if let Ok(node) = FormatCodec::from_str_async(content, options).await {
            return Ok(node);
        }

        bail!(
            "Unable to decode from string with format `{}`: no matching codec found",
            format_spec.title
        )
    }

    /// Decode a document node from a file system path
    #[allow(clippy::needless_update)]
    async fn from_path(
        &self,
        path: &Path,
        format: &str,
        options: Option<DecodeOptions>,
    ) -> Result<Node> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(DecodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, from_path, path, options) {
            return future.await;
        }

        bail!(
            "Unable to decode from path with format `{}`: no matching codec found",
            format_spec.title
        )
    }

    /// Encode a document node to a string
    #[allow(unused_variables)]
    async fn to_string(
        &self,
        node: &Node,
        format: &str,
        options: Option<EncodeOptions>,
    ) -> Result<String> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(EncodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, to_string_async, node, options) {
            return future.await;
        }

        bail!(
            "Unable to encode to string of format `{}`: no matching codec found",
            format_spec.title
        )
    }

    /// Encode a document node to a file system path
    async fn to_path(
        &self,
        node: &Node,
        path: &Path,
        format: &str,
        options: Option<EncodeOptions>,
    ) -> Result<()> {
        let format = match_name(format);
        let format_spec = format.spec();

        let options = Some(EncodeOptions {
            format: Some(format_spec.extension.clone()),
            ..options.unwrap_or_default()
        });

        if let Some(future) = dispatch_builtins!(format, to_path, node, path, options) {
            return future.await;
        }

        bail!(
            "Unable to encode to path with format `{}`: no matching codec found",
            format_spec.title
        )
    }
}

impl Default for Codecs {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(feature = "cli")]
pub mod commands {
    use super::*;
    use cli_utils::{result, Result, Run};
    use codec::async_trait::async_trait;
    use structopt::StructOpt;

    /// Manage codecs
    ///
    /// In Stencila, a "codec" is responsible for converting documents
    /// to ("encoding") and from ("decoding") a format (e.g. Markdown).
    /// This command alls you to list the available codecs and see their
    /// specifications (e.g. which formats they support).
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Command {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        List(List),
        Show(Show),
    }

    #[async_trait]
    impl Run for Command {
        async fn run(&self) -> Result {
            let Self { action } = self;
            match action {
                Action::List(action) => action.run().await,
                Action::Show(action) => action.run().await,
            }
        }
    }

    /// List the codecs available
    ///
    /// The list of available codecs includes those that are built into the Stencila
    /// binary (e.g. `html`) as well as any codecs provided by plugins.
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct List {}

    #[async_trait]
    impl Run for List {
        async fn run(&self) -> Result {
            let list = CODECS.list();
            let table = CODECS.table();
            result::new("md", &table, &list)
        }
    }

    /// Show the specifications of a codec
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Show {
        /// The label of the codec
        ///
        /// To get the list of codec labels use `stencila codecs list`.
        label: String,
    }

    #[async_trait]
    impl Run for Show {
        async fn run(&self) -> Result {
            let codec = CODECS.get(&self.label)?;
            result::value(codec)
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>sdk: don't leak handles in grpc::Client (#1124)<commit_after><|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Concurrency-friendly shared state

use core::ty::Unsafe;
use core::ops::{Deref, DerefMut};
use core::kinds::{Share, Send};
use core::kinds::marker;

use hal::cortex_m3::sched::NoInterrupts;

/// This allows safe sharing of state, ensuring access occurs only
/// when in a critical section.
#[allow(missing_doc)]
pub struct Shared<T> {
  pub value: Unsafe<T>,
  pub invariant: marker::InvariantType<T>,
}

/// A reference to a shared value
pub struct SharedRef<'a, T: 'a> {
  ptr: &'a Shared<T>,
  crit: &'a NoInterrupts
}

impl<T> Shared<T> {
  /// Create a new `Shared` value
  pub fn new(value: T) -> Shared<T> {
    Shared {
      value: Unsafe::new(value),
      invariant: marker::InvariantType,
    }
  }

  /// Borrow a reference to the value
  pub fn borrow<'a>(&'a self, crit: &'a NoInterrupts) -> SharedRef<'a, T> {
    SharedRef {ptr: self, crit: crit}
  }
}

impl<'a, T> Deref<T> for SharedRef<'a, T> {
  fn deref<'a>(&'a self) -> &'a T {
    unsafe {
      &*self.ptr.value.get()
    }
  }
}

impl<'a, T> DerefMut<T> for SharedRef<'a, T> {
  fn deref_mut<'a>(&'a mut self) -> &'a mut T {
    unsafe {
      &mut *self.ptr.value.get()
    }
  }
}

impl<T: Send> Share for Shared<T> {}
<commit_msg>util::shared: Allow dead code for NoInterrupts<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Concurrency-friendly shared state

use core::ty::Unsafe;
use core::ops::{Deref, DerefMut};
use core::kinds::{Share, Send};
use core::kinds::marker;

use hal::cortex_m3::sched::NoInterrupts;

/// This allows safe sharing of state, ensuring access occurs only
/// when in a critical section.
#[allow(missing_doc)]
pub struct Shared<T> {
  pub value: Unsafe<T>,
  pub invariant: marker::InvariantType<T>,
}

/// A reference to a shared value
pub struct SharedRef<'a, T: 'a> {
  ptr: &'a Shared<T>,
  #[allow(dead_code)]
  crit: &'a NoInterrupts
}

impl<T> Shared<T> {
  /// Create a new `Shared` value
  pub fn new(value: T) -> Shared<T> {
    Shared {
      value: Unsafe::new(value),
      invariant: marker::InvariantType,
    }
  }

  /// Borrow a reference to the value
  pub fn borrow<'a>(&'a self, crit: &'a NoInterrupts) -> SharedRef<'a, T> {
    SharedRef {ptr: self, crit: crit}
  }
}

impl<'a, T> Deref<T> for SharedRef<'a, T> {
  fn deref<'a>(&'a self) -> &'a T {
    unsafe {
      &*self.ptr.value.get()
    }
  }
}

impl<'a, T> DerefMut<T> for SharedRef<'a, T> {
  fn deref_mut<'a>(&'a mut self) -> &'a mut T {
    unsafe {
      &mut *self.ptr.value.get()
    }
  }
}

impl<T: Send> Share for Shared<T> {}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::cmp;
use std::mem;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{self, Receiver, TryRecvError};
use std::sync::Arc;
use std::thread::{self, JoinHandle};

use model::ttable::{Entry, EvalType, TTable};
use model::{Board, Move, Outcome};

const INFINITY: i16 = 0x7FFF;
const NEG_INFINITY: i16 = -0x7FFF;
const LOSE: i16 = -0x4000;
// Small contempt factor to discourage draws
const DRAW: i16 = 1;

pub enum AI {
    Idle,
    // Either the AI thread is running, or there is a move waiting to be received
    Thinking {
        move_recv: Receiver<Move>,
        // We store and load this atomic with Ordering::Relaxed. It *should* be fine because it
        // doesn't interact with any other atomics--all we want to do is tell the AI thread to stop
        // searching for a move
        stop_signal: Arc<AtomicBool>,
        handle: JoinHandle<()>,
    },
}

impl AI {
    pub fn new() -> AI {
        AI::Idle
    }

    pub fn is_idle(&self) -> bool {
        match self {
            AI::Idle => true,
            AI::Thinking { .. } => false,
        }
    }

    pub fn stop(&mut self) {
        if let AI::Thinking { stop_signal, .. } = self {
            stop_signal.store(true, Ordering::Relaxed);
            *self = AI::Idle;
        }
    }

    pub fn try_recv(&mut self) -> Option<Move> {
        use self::TryRecvError::*;

        match self {
            AI::Idle => None,
            AI::Thinking { move_recv, .. } => match move_recv.try_recv() {
                Ok(mv) => {
                    *self = AI::Idle;
                    Some(mv)
                }
                Err(Empty) => None,
                Err(Disconnected) => panic!("Tried to receive move from disconnected sender"),
            },
        }
    }

    pub fn think(&mut self, board: Board, board_list: Vec<Board>, depth: u8) {
        assert_ne!(depth, 0);

        let prev_ai = mem::replace(self, AI::Idle);

        let (move_sender, move_recv) = mpsc::channel();
        let stop_signal = Arc::new(AtomicBool::new(false));
        let stop_signal_clone = stop_signal.clone();

        let handle = thread::spawn(move || {
            if let AI::Thinking {
                stop_signal,
                handle,
                ..
            } = prev_ai
            {
                stop_signal.store(true, Ordering::Relaxed);
                handle
                    .join()
                    .expect("Old AI thread panicked when new AI thread joined on it");
            }

            // Only take positions after the last irreversible move
            let mut board_list: Vec<_> = board_list
                .into_iter()
                .rev()
                .take_while(|b| b.vitals() == board.vitals())
                .collect();
            board_list.reverse();

            // 2-ply iterative deepening
            let mut moves: Vec<(Move, i16)> = board
                .generate_moves()
                .into_iter()
                .map(|mv| {
                    let mut new_board = board;
                    new_board.apply_move(&mv);

                    let score =
                        -alphabeta_negamax(&new_board, &mut board_list, NEG_INFINITY, INFINITY, 1);
                    (mv, score)
                })
                .collect();

            moves.sort_by(|&(_, a), &(_, b)| b.cmp(&a));

            let mut max_score = NEG_INFINITY;
            let mut best_move = None;
            for (mv, _) in moves {
                if stop_signal_clone.load(Ordering::Relaxed) {
                    return;
                }

                let mut new_board = board;
                new_board.apply_move(&mv);

                let score = -alphabeta_negamax(
                    &new_board,
                    &mut board_list,
                    NEG_INFINITY,
                    -max_score,
                    depth - 1,
                );
                if score > max_score {
                    max_score = score;
                    best_move = Some(mv);
                }
            }

            match best_move {
                Some(mv) => move_sender.send(mv).expect("AI failed to send Move"),
                None => panic!("AI failed to find a move"),
            }
        });

        *self = AI::Thinking {
            move_recv,
            stop_signal,
            handle,
        }
    }
}

fn alphabeta_negamax(
    board: &Board,
    // This list does not include the current board
    mut board_list: &mut Vec<Board>,
    mut alpha: i16,
    mut beta: i16,
    depth: u8,
) -> i16 {
    let set_ttable = |eval_type, score| {
        let zobrist = board.zobrist();
        TTable::set(
            zobrist,
            Entry {
                eval_type,
                depth,
                score,
                zobrist,
            },
        );
    };

    match board.outcome() {
        Outcome::Draw => {
            // This only works because the draw Outcome does not consider draw by repetition
            set_ttable(EvalType::Exact, DRAW);
            return DRAW;
        }
        Outcome::Win(color) => {
            assert_ne!(color, board.turn());
            // Weight score by depth to encourage shorter wins. The shorter the win, the greater
            // `depth` will be, and so the larger the score will be. This also encourages the AI to
            // prolong a loss.
            let score = LOSE - i16::from(depth);
            set_ttable(EvalType::Exact, score);
            return score;
        }
        Outcome::InProgress => {}
    }

    if let Some(entry) = TTable::get(board.zobrist()) {
        if board_list.len() >= 8 {
            if board_list.iter().filter(|&&b| b == *board).count() >= 2 {
                return DRAW;
            }
        }

        if entry.zobrist == board.zobrist() && entry.depth >= depth {
            match entry.eval_type {
                EvalType::Exact => {
                    return entry.score;
                }
                EvalType::Beta => {
                    if entry.score >= beta {
                        return entry.score;
                    }
                    beta = entry.score;
                }
            }
        }
    }

    if depth == 0 {
        evaluate(board)
    } else {
        let mut best_score = NEG_INFINITY;

        let moves = board.generate_moves();
        for mv in moves {
            let mut new_board = *board;
            new_board.apply_move(&mv);

            board_list.push(*board);
            let score = -alphabeta_negamax(&new_board, &mut board_list, -beta, -alpha, depth - 1);
            board_list.pop();

            best_score = cmp::max(score, best_score);

            if score >= beta {
                set_ttable(EvalType::Beta, score);
                return beta;
            } else if score > alpha {
                alpha = score;
            }
        }
        set_ttable(EvalType::Exact, best_score);
        alpha
    }
}

fn evaluate(board: &Board) -> i16 {
    use model::Color::*;

    let wp = 100 * i16::from(board.pieces(White));
    let bp = 100 * i16::from(board.pieces(Black));
    let wh = 50 * i16::from(board.hexes(White));
    let bh = 50 * i16::from(board.hexes(Black));

    match board.turn() {
        White => (wp + wh) - (bp + bh),
        Black => (bp + bh) - (wp + wh),
    }
}
<commit_msg>Collapse if<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::cmp;
use std::mem;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{self, Receiver, TryRecvError};
use std::sync::Arc;
use std::thread::{self, JoinHandle};

use model::ttable::{Entry, EvalType, TTable};
use model::{Board, Move, Outcome};

const INFINITY: i16 = 0x7FFF;
const NEG_INFINITY: i16 = -0x7FFF;
const LOSE: i16 = -0x4000;
// Small contempt factor to discourage draws
const DRAW: i16 = 1;

pub enum AI {
    Idle,
    // Either the AI thread is running, or there is a move waiting to be received
    Thinking {
        move_recv: Receiver<Move>,
        // We store and load this atomic with Ordering::Relaxed. It *should* be fine because it
        // doesn't interact with any other atomics--all we want to do is tell the AI thread to stop
        // searching for a move
        stop_signal: Arc<AtomicBool>,
        handle: JoinHandle<()>,
    },
}

impl AI {
    pub fn new() -> AI {
        AI::Idle
    }

    pub fn is_idle(&self) -> bool {
        match self {
            AI::Idle => true,
            AI::Thinking { .. } => false,
        }
    }

    pub fn stop(&mut self) {
        if let AI::Thinking { stop_signal, .. } = self {
            stop_signal.store(true, Ordering::Relaxed);
            *self = AI::Idle;
        }
    }

    pub fn try_recv(&mut self) -> Option<Move> {
        use self::TryRecvError::*;

        match self {
            AI::Idle => None,
            AI::Thinking { move_recv, .. } => match move_recv.try_recv() {
                Ok(mv) => {
                    *self = AI::Idle;
                    Some(mv)
                }
                Err(Empty) => None,
                Err(Disconnected) => panic!("Tried to receive move from disconnected sender"),
            },
        }
    }

    pub fn think(&mut self, board: Board, board_list: Vec<Board>, depth: u8) {
        assert_ne!(depth, 0);

        let prev_ai = mem::replace(self, AI::Idle);

        let (move_sender, move_recv) = mpsc::channel();
        let stop_signal = Arc::new(AtomicBool::new(false));
        let stop_signal_clone = stop_signal.clone();

        let handle = thread::spawn(move || {
            if let AI::Thinking {
                stop_signal,
                handle,
                ..
            } = prev_ai
            {
                stop_signal.store(true, Ordering::Relaxed);
                handle
                    .join()
                    .expect("Old AI thread panicked when new AI thread joined on it");
            }

            // Only take positions after the last irreversible move
            let mut board_list: Vec<_> = board_list
                .into_iter()
                .rev()
                .take_while(|b| b.vitals() == board.vitals())
                .collect();
            board_list.reverse();

            // 2-ply iterative deepening
            let mut moves: Vec<(Move, i16)> = board
                .generate_moves()
                .into_iter()
                .map(|mv| {
                    let mut new_board = board;
                    new_board.apply_move(&mv);

                    let score =
                        -alphabeta_negamax(&new_board, &mut board_list, NEG_INFINITY, INFINITY, 1);
                    (mv, score)
                })
                .collect();

            moves.sort_by(|&(_, a), &(_, b)| b.cmp(&a));

            let mut max_score = NEG_INFINITY;
            let mut best_move = None;
            for (mv, _) in moves {
                if stop_signal_clone.load(Ordering::Relaxed) {
                    return;
                }

                let mut new_board = board;
                new_board.apply_move(&mv);

                let score = -alphabeta_negamax(
                    &new_board,
                    &mut board_list,
                    NEG_INFINITY,
                    -max_score,
                    depth - 1,
                );
                if score > max_score {
                    max_score = score;
                    best_move = Some(mv);
                }
            }

            match best_move {
                Some(mv) => move_sender.send(mv).expect("AI failed to send Move"),
                None => panic!("AI failed to find a move"),
            }
        });

        *self = AI::Thinking {
            move_recv,
            stop_signal,
            handle,
        }
    }
}

fn alphabeta_negamax(
    board: &Board,
    // This list does not include the current board
    mut board_list: &mut Vec<Board>,
    mut alpha: i16,
    mut beta: i16,
    depth: u8,
) -> i16 {
    let set_ttable = |eval_type, score| {
        let zobrist = board.zobrist();
        TTable::set(
            zobrist,
            Entry {
                eval_type,
                depth,
                score,
                zobrist,
            },
        );
    };

    match board.outcome() {
        Outcome::Draw => {
            // This only works because the draw Outcome does not consider draw by repetition
            set_ttable(EvalType::Exact, DRAW);
            return DRAW;
        }
        Outcome::Win(color) => {
            assert_ne!(color, board.turn());
            // Weight score by depth to encourage shorter wins. The shorter the win, the greater
            // `depth` will be, and so the larger the score will be. This also encourages the AI to
            // prolong a loss.
            let score = LOSE - i16::from(depth);
            set_ttable(EvalType::Exact, score);
            return score;
        }
        Outcome::InProgress => {}
    }

    if let Some(entry) = TTable::get(board.zobrist()) {
        if board_list.len() >= 8 && board_list.iter().filter(|&&b| b == *board).count() >= 2 {
            return DRAW;
        }

        if entry.zobrist == board.zobrist() && entry.depth >= depth {
            match entry.eval_type {
                EvalType::Exact => {
                    return entry.score;
                }
                EvalType::Beta => {
                    if entry.score >= beta {
                        return entry.score;
                    }
                    beta = entry.score;
                }
            }
        }
    }

    if depth == 0 {
        evaluate(board)
    } else {
        let mut best_score = NEG_INFINITY;

        let moves = board.generate_moves();
        for mv in moves {
            let mut new_board = *board;
            new_board.apply_move(&mv);

            board_list.push(*board);
            let score = -alphabeta_negamax(&new_board, &mut board_list, -beta, -alpha, depth - 1);
            board_list.pop();

            best_score = cmp::max(score, best_score);

            if score >= beta {
                set_ttable(EvalType::Beta, score);
                return beta;
            } else if score > alpha {
                alpha = score;
            }
        }
        set_ttable(EvalType::Exact, best_score);
        alpha
    }
}

fn evaluate(board: &Board) -> i16 {
    use model::Color::*;

    let wp = 100 * i16::from(board.pieces(White));
    let bp = 100 * i16::from(board.pieces(Black));
    let wh = 50 * i16::from(board.hexes(White));
    let bh = 50 * i16::from(board.hexes(Black));

    match board.turn() {
        White => (wp + wh) - (bp + bh),
        Black => (bp + bh) - (wp + wh),
    }
}
<|endoftext|>


<commit_before>use ffi;
use std::ptr;
use types::*;
use ffi::MaybeError;

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    input_device: ffi::PmDeviceId,
    buffer_size: i32,
}

const EVENT_BUFFER_SIZE: usize = 128;
impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(input_device: PortMidiDeviceId, buffer_size: i32) -> InputPort {
        InputPort {
            stream: ptr::null(),
            input_device: input_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> Result<()> {
        Result::from(unsafe {
            ffi::Pm_OpenInput(&self.stream,
                              self.input_device,
                              ptr::null(),
                              self.buffer_size,
                              ptr::null(),
                              ptr::null())
        })
    }

    pub fn read_n(&mut self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > EVENT_BUFFER_SIZE {
            EVENT_BUFFER_SIZE as i32
        } else {
            cnt as i32
        };
        let mut event_buffer = [ffi::PmEvent::default(); EVENT_BUFFER_SIZE];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        if res < 0 {
            let err = ffi::PmError::try_from(res).unwrap();
            // TODO: Return the error
            println!("error: {:?}", err);
            return Ok(None);
        } else if res == 0 {
            Ok(None)
        } else {
            // remove mutability and replace return value
            let mut events = (0..res as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
            Ok(Some(events))
        }
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    /// TODO: call `read_n`
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }

    /// Closes the input, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Close(self.stream) })
    }
}

// Output
// ------
/// Representation of an output midi port
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    output_device: ffi::PmDeviceId,
    buffer_size: i32,
}
impl OutputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(output_device: PortMidiDeviceId, buffer_size: i32) -> OutputPort {
        OutputPort {
            stream: ptr::null(),
            output_device: output_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> Result<()> {
        Result::from(unsafe {
            ffi::Pm_OpenOutput(&self.stream,
                               self.output_device,
                               ptr::null(),
                               self.buffer_size,
                               ptr::null(),
                               ptr::null(),
                               0)
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Closes the midi stream, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Close(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> Result<()> {
        let event = midi_event.into();
        Result::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
<commit_msg>Remove mutability qualifier<commit_after>use ffi;
use std::ptr;
use types::*;
use ffi::MaybeError;

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    input_device: ffi::PmDeviceId,
    buffer_size: i32,
}

const EVENT_BUFFER_SIZE: usize = 128;
impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(input_device: PortMidiDeviceId, buffer_size: i32) -> InputPort {
        InputPort {
            stream: ptr::null(),
            input_device: input_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> Result<()> {
        Result::from(unsafe {
            ffi::Pm_OpenInput(&self.stream,
                              self.input_device,
                              ptr::null(),
                              self.buffer_size,
                              ptr::null(),
                              ptr::null())
        })
    }

    pub fn read_n(&mut self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > EVENT_BUFFER_SIZE {
            EVENT_BUFFER_SIZE as i32
        } else {
            cnt as i32
        };
        let mut event_buffer = [ffi::PmEvent::default(); EVENT_BUFFER_SIZE];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        if res < 0 {
            let err = ffi::PmError::try_from(res).unwrap();
            // TODO: Return the error
            println!("error: {:?}", err);
            return Ok(None);
        } else if res == 0 {
            Ok(None)
        } else {
            // remove mutability and replace return value
            let events = (0..res as usize)
                             .map(|i| MidiEvent::from(event_buffer[i].clone()))
                             .collect::<Vec<MidiEvent>>();
            Ok(Some(events))
        }
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    /// TODO: call `read_n`
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }

    /// Closes the input, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Close(self.stream) })
    }
}

// Output
// ------
/// Representation of an output midi port
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    output_device: ffi::PmDeviceId,
    buffer_size: i32,
}
impl OutputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(output_device: PortMidiDeviceId, buffer_size: i32) -> OutputPort {
        OutputPort {
            stream: ptr::null(),
            output_device: output_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self) -> Result<()> {
        Result::from(unsafe {
            ffi::Pm_OpenOutput(&self.stream,
                               self.output_device,
                               ptr::null(),
                               self.buffer_size,
                               ptr::null(),
                               ptr::null(),
                               0)
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Closes the midi stream, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Close(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> Result<()> {
        let event = midi_event.into();
        Result::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::cmp;
use FrameInvariants;
use FrameState;
use partition::BlockSize;
use context::BlockOffset;
use partition::MotionVector;
use partition::LAST_FRAME;
use plane::PlaneOffset;
use context::BLOCK_TO_PLANE_SHIFT;

pub fn motion_estimation(fi: &FrameInvariants, fs: &mut FrameState, bsize: BlockSize,
                         bo: &BlockOffset, ref_frame: usize) -> MotionVector {

  match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME]] {
    Some(ref rec) => {
      let po = PlaneOffset { x: bo.x << BLOCK_TO_PLANE_SHIFT, y: bo.y << BLOCK_TO_PLANE_SHIFT };
      let range = 16 as usize;
      let blk_w = bsize.width();
      let blk_h = bsize.height();
      let x_lo = cmp::max(0, po.x as isize - range as isize) as usize;
      let x_hi = cmp::min(fs.input.planes[0].cfg.width - blk_w, po.x + range);
      let y_lo = cmp::max(0, po.y as isize - range as isize) as usize;
      let y_hi = cmp::min(fs.input.planes[0].cfg.height - blk_h, po.y + range);

      let stride_org = fs.input.planes[0].cfg.stride;
      let stride_ref = rec.planes[0].cfg.stride;

      let mut lowest_sad = 128*128*4096 as u32;
      let mut best_mv = MotionVector { row: 0, col: 0 };

      for y in (y_lo..y_hi).step_by(2) {
        for x in (x_lo..x_hi).step_by(2) {
          let mut sad = 0 as u32;
          let mut plane_org = fs.input.planes[0].slice(&po);
          let mut plane_ref = rec.planes[0].slice(&PlaneOffset { x: x, y: y });

          for _r in 0..blk_h {
            {
              let slice_org = plane_org.as_slice_w_width(blk_w);
              let slice_ref = plane_ref.as_slice_w_width(blk_w);
              sad += slice_org.iter().zip(slice_ref).map(|(&a, &b)| (a as i32 - b as i32).abs() as u32).sum::<u32>();
            }
            plane_org.y += 1;
            plane_ref.y += 1;
          }

          if sad < lowest_sad {
            lowest_sad = sad;
            best_mv = MotionVector { row: 8*(y as i16 - po.y as i16), col: 8*(x as i16 - po.x as i16) }
          }

        }
      }
      best_mv
    },

    None => MotionVector { row: 0, col : 0 }
  }
}
<commit_msg>Remove superfluous lines of code<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::cmp;
use FrameInvariants;
use FrameState;
use partition::BlockSize;
use context::BlockOffset;
use partition::MotionVector;
use partition::LAST_FRAME;
use plane::PlaneOffset;
use context::BLOCK_TO_PLANE_SHIFT;

pub fn motion_estimation(fi: &FrameInvariants, fs: &mut FrameState, bsize: BlockSize,
                         bo: &BlockOffset, ref_frame: usize) -> MotionVector {

  match fi.rec_buffer.frames[fi.ref_frames[ref_frame - LAST_FRAME]] {
    Some(ref rec) => {
      let po = PlaneOffset { x: bo.x << BLOCK_TO_PLANE_SHIFT, y: bo.y << BLOCK_TO_PLANE_SHIFT };
      let range = 16 as usize;
      let blk_w = bsize.width();
      let blk_h = bsize.height();
      let x_lo = cmp::max(0, po.x as isize - range as isize) as usize;
      let x_hi = cmp::min(fs.input.planes[0].cfg.width - blk_w, po.x + range);
      let y_lo = cmp::max(0, po.y as isize - range as isize) as usize;
      let y_hi = cmp::min(fs.input.planes[0].cfg.height - blk_h, po.y + range);

      let mut lowest_sad = 128*128*4096 as u32;
      let mut best_mv = MotionVector { row: 0, col: 0 };

      for y in (y_lo..y_hi).step_by(2) {
        for x in (x_lo..x_hi).step_by(2) {
          let mut sad = 0 as u32;
          let mut plane_org = fs.input.planes[0].slice(&po);
          let mut plane_ref = rec.planes[0].slice(&PlaneOffset { x: x, y: y });

          for _r in 0..blk_h {
            {
              let slice_org = plane_org.as_slice_w_width(blk_w);
              let slice_ref = plane_ref.as_slice_w_width(blk_w);
              sad += slice_org.iter().zip(slice_ref).map(|(&a, &b)| (a as i32 - b as i32).abs() as u32).sum::<u32>();
            }
            plane_org.y += 1;
            plane_ref.y += 1;
          }

          if sad < lowest_sad {
            lowest_sad = sad;
            best_mv = MotionVector { row: 8*(y as i16 - po.y as i16), col: 8*(x as i16 - po.x as i16) }
          }

        }
      }
      best_mv
    },

    None => MotionVector { row: 0, col : 0 }
  }
}
<|endoftext|>


<commit_before>use alloc::borrow::Cow;
use alloc::vec::Vec;
use std::slice;

use goblin::pe;

use {
    Machine, Object, ObjectSection, ObjectSegment, SectionKind, Symbol, SymbolKind, SymbolMap,
};

/// A PE object file.
#[derive(Debug)]
pub struct PeFile<'data> {
    pe: pe::PE<'data>,
    data: &'data [u8],
}

/// An iterator over the loadable sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSegmentIterator<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    iter: slice::Iter<'file, pe::section_table::SectionTable>,
}

/// A loadable section of a `PeFile`.
#[derive(Debug)]
pub struct PeSegment<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    section: &'file pe::section_table::SectionTable,
}

/// An iterator over the sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSectionIterator<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    iter: slice::Iter<'file, pe::section_table::SectionTable>,
}

/// A section of a `PeFile`.
#[derive(Debug)]
pub struct PeSection<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    section: &'file pe::section_table::SectionTable,
}

/// An iterator over the symbols of a `PeFile`.
#[derive(Debug)]
pub struct PeSymbolIterator<'data, 'file>
where
    'data: 'file,
{
    exports: slice::Iter<'file, pe::export::Export<'data>>,
    imports: slice::Iter<'file, pe::import::Import<'data>>,
}

impl<'data> PeFile<'data> {
    /// Get the PE headers of the file.
    // TODO: this is temporary to allow access to features this crate doesn't provide yet
    #[inline]
    pub fn pe(&self) -> &pe::PE<'data> {
        &self.pe
    }

    /// Parse the raw PE file data.
    pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
        let pe = pe::PE::parse(data).map_err(|_| "Could not parse PE header")?;
        Ok(PeFile { pe, data })
    }
}

impl<'data, 'file> Object<'data, 'file> for PeFile<'data>
where
    'data: 'file,
{
    type Segment = PeSegment<'data, 'file>;
    type SegmentIterator = PeSegmentIterator<'data, 'file>;
    type Section = PeSection<'data, 'file>;
    type SectionIterator = PeSectionIterator<'data, 'file>;
    type SymbolIterator = PeSymbolIterator<'data, 'file>;

    fn machine(&self) -> Machine {
        match self.pe.header.coff_header.machine {
            // TODO: Arm/Arm64
            pe::header::COFF_MACHINE_X86 => Machine::X86,
            pe::header::COFF_MACHINE_X86_64 => Machine::X86_64,
            _ => Machine::Other,
        }
    }

    fn segments(&'file self) -> PeSegmentIterator<'data, 'file> {
        PeSegmentIterator {
            file: self,
            iter: self.pe.sections.iter(),
        }
    }

    fn section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>> {
        for section in &self.pe.sections {
            if let Ok(name) = section.name() {
                if name == section_name {
                    return Some(Cow::from(
                        &self.data[section.pointer_to_raw_data as usize..]
                            [..section.size_of_raw_data as usize],
                    ));
                }
            }
        }
        None
    }

    fn sections(&'file self) -> PeSectionIterator<'data, 'file> {
        PeSectionIterator {
            file: self,
            iter: self.pe.sections.iter(),
        }
    }

    fn symbols(&'file self) -> PeSymbolIterator<'data, 'file> {
        // TODO: return COFF symbols for object files
        PeSymbolIterator {
            exports: [].iter(),
            imports: [].iter(),
        }
    }

    fn dynamic_symbols(&'file self) -> PeSymbolIterator<'data, 'file> {
        PeSymbolIterator {
            exports: self.pe.exports.iter(),
            imports: self.pe.imports.iter(),
        }
    }

    fn symbol_map(&self) -> SymbolMap<'data> {
        // TODO: untested
        let mut symbols: Vec<_> = self.symbols().filter(SymbolMap::filter).collect();
        symbols.sort_by_key(|x| x.address);
        SymbolMap { symbols }
    }

    #[inline]
    fn is_little_endian(&self) -> bool {
        // TODO: always little endian?  The COFF header has some bits in the
        // characteristics flags, but these are obsolete.
        true
    }

    #[inline]
    fn has_debug_symbols(&self) -> bool {
        // TODO: look at what the mingw toolchain does with DWARF-in-PE, and also
        // whether CodeView-in-PE still works?
        false
    }

    fn entry(&self) -> u64 {
        self.pe.entry as u64
    }
}

impl<'data, 'file> Iterator for PeSegmentIterator<'data, 'file> {
    type Item = PeSegment<'data, 'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| PeSegment {
            file: self.file,
            section,
        })
    }
}

impl<'data, 'file> ObjectSegment<'data> for PeSegment<'data, 'file> {
    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size)
    }

    fn data(&self) -> &'data [u8] {
        &self.file.data[self.section.pointer_to_raw_data as usize..]
            [..self.section.size_of_raw_data as usize]
    }

    #[inline]
    fn name(&self) -> Option<&str> {
        self.section.name().ok()
    }
}

impl<'data, 'file> Iterator for PeSectionIterator<'data, 'file> {
    type Item = PeSection<'data, 'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| PeSection {
            file: self.file,
            section,
        })
    }
}

impl<'data, 'file> ObjectSection<'data> for PeSection<'data, 'file> {
    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size)
    }

    fn data(&self) -> Cow<'data, [u8]> {
        Cow::from(
            &self.file.data[self.section.pointer_to_raw_data as usize..]
                [..self.section.size_of_raw_data as usize],
        )
    }

    fn name(&self) -> Option<&str> {
        self.section.name().ok()
    }

    #[inline]
    fn segment_name(&self) -> Option<&str> {
        None
    }

    #[inline]
    fn kind(&self) -> SectionKind {
        if self.section.characteristics
            & (pe::section_table::IMAGE_SCN_CNT_CODE | pe::section_table::IMAGE_SCN_MEM_EXECUTE)
            != 0
        {
            SectionKind::Text
        } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_INITIALIZED_DATA
            != 0
        {
            SectionKind::Data
        } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_UNINITIALIZED_DATA
            != 0
        {
            SectionKind::UninitializedData
        } else {
            SectionKind::Unknown
        }
    }
}

impl<'data, 'file> Iterator for PeSymbolIterator<'data, 'file> {
    type Item = Symbol<'data>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(export) = self.exports.next() {
            return Some(Symbol {
                kind: SymbolKind::Unknown,
                section_kind: Some(SectionKind::Unknown),
                global: true,
                name: export.name,
                address: export.rva as u64,
                size: 0,
            });
        }
        if let Some(import) = self.imports.next() {
            let name = match import.name {
                Cow::Borrowed(name) => Some(name),
                _ => None,
            };
            return Some(Symbol {
                kind: SymbolKind::Unknown,
                section_kind: None,
                global: true,
                name: name,
                address: 0,
                size: 0,
            });
        }
        None
    }
}
<commit_msg>Issue #40 -- Support DWARF-in-PE<commit_after>use alloc::borrow::Cow;
use alloc::vec::Vec;
use std::slice;

use goblin::pe;
use scroll::Pread;

use {
    Machine, Object, ObjectSection, ObjectSegment, SectionKind, Symbol, SymbolKind, SymbolMap,
};

/// A PE object file.
#[derive(Debug)]
pub struct PeFile<'data> {
    pe: pe::PE<'data>,
    symbol_table_offset: usize,
    data: &'data [u8],
}

/// An iterator over the loadable sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSegmentIterator<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    iter: slice::Iter<'file, pe::section_table::SectionTable>,
}

/// A loadable section of a `PeFile`.
#[derive(Debug)]
pub struct PeSegment<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    section: &'file pe::section_table::SectionTable,
}

/// An iterator over the sections of a `PeFile`.
#[derive(Debug)]
pub struct PeSectionIterator<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    iter: slice::Iter<'file, pe::section_table::SectionTable>,
}

/// A section of a `PeFile`.
#[derive(Debug)]
pub struct PeSection<'data, 'file>
where
    'data: 'file,
{
    file: &'file PeFile<'data>,
    section: &'file pe::section_table::SectionTable,
}

/// An iterator over the symbols of a `PeFile`.
#[derive(Debug)]
pub struct PeSymbolIterator<'data, 'file>
where
    'data: 'file,
{
    exports: slice::Iter<'file, pe::export::Export<'data>>,
    imports: slice::Iter<'file, pe::import::Import<'data>>,
}

impl<'data> PeFile<'data> {
    /// Get the PE headers of the file.
    // TODO: this is temporary to allow access to features this crate doesn't provide yet
    #[inline]
    pub fn pe(&self) -> &pe::PE<'data> {
        &self.pe
    }

    /// Parse the raw PE file data.
    pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
        let pe = pe::PE::parse(data).map_err(|_| "Could not parse PE header")?;
        // get offset to secret symbol table that follows the COFF symbol table
        let symbol_table_offset = (
            pe.header.coff_header.pointer_to_symbol_table +
                pe.header.coff_header.number_of_symbol_table * 18
        ) as usize;
        Ok(PeFile { pe, symbol_table_offset, data })
    }

    /// Get section name from special PE symbol table
    fn get_section_name(
        &self,
        section: &'data pe::section_table::SectionTable,
    ) -> Option<&'data str> {
        let mut name = section.name().ok()?;
        // if name start with "/" then it's an index into the secret symbol table
        let mut name_chars = name.chars();
        if name_chars.next() == Some('/') {
            let index = name_chars.as_str().parse::<usize>().ok()?;
            name = self.data.pread(self.symbol_table_offset + index).ok()?;
        };
        Some(name)
    }
}

impl<'data, 'file> Object<'data, 'file> for PeFile<'data>
where
    'data: 'file,
{
    type Segment = PeSegment<'data, 'file>;
    type SegmentIterator = PeSegmentIterator<'data, 'file>;
    type Section = PeSection<'data, 'file>;
    type SectionIterator = PeSectionIterator<'data, 'file>;
    type SymbolIterator = PeSymbolIterator<'data, 'file>;

    fn machine(&self) -> Machine {
        match self.pe.header.coff_header.machine {
            // TODO: Arm/Arm64
            pe::header::COFF_MACHINE_X86 => Machine::X86,
            pe::header::COFF_MACHINE_X86_64 => Machine::X86_64,
            _ => Machine::Other,
        }
    }

    fn segments(&'file self) -> PeSegmentIterator<'data, 'file> {
        PeSegmentIterator {
            file: self,
            iter: self.pe.sections.iter(),
        }
    }

    fn section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>> {
        for section in &self.pe.sections {
            if let Some(name) = self.get_section_name(&section) {
                if name == section_name {
                    return Some(Cow::from(
                        &self.data[section.pointer_to_raw_data as usize..]
                            [..section.virtual_size as usize],
                    ));
                }
            }
        }
        None
    }

    fn sections(&'file self) -> PeSectionIterator<'data, 'file> {
        PeSectionIterator {
            file: self,
            iter: self.pe.sections.iter(),
        }
    }

    fn symbols(&'file self) -> PeSymbolIterator<'data, 'file> {
        // TODO: return COFF symbols for object files
        PeSymbolIterator {
            exports: [].iter(),
            imports: [].iter(),
        }
    }

    fn dynamic_symbols(&'file self) -> PeSymbolIterator<'data, 'file> {
        PeSymbolIterator {
            exports: self.pe.exports.iter(),
            imports: self.pe.imports.iter(),
        }
    }

    fn symbol_map(&self) -> SymbolMap<'data> {
        // TODO: untested
        let mut symbols: Vec<_> = self.symbols().filter(SymbolMap::filter).collect();
        symbols.sort_by_key(|x| x.address);
        SymbolMap { symbols }
    }

    #[inline]
    fn is_little_endian(&self) -> bool {
        // TODO: always little endian?  The COFF header has some bits in the
        // characteristics flags, but these are obsolete.
        true
    }

    fn has_debug_symbols(&self) -> bool {
        // TODO: check if CodeView-in-PE still works
        for section in &self.pe.sections {
            if let Some(name) = self.get_section_name(&section) {
                if name == ".debug_info" {
                    return true;
                }
            }
        }
        false
    }

    fn entry(&self) -> u64 {
        self.pe.entry as u64
    }
}

impl<'data, 'file> Iterator for PeSegmentIterator<'data, 'file> {
    type Item = PeSegment<'data, 'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| PeSegment {
            file: self.file,
            section,
        })
    }
}

impl<'data, 'file> ObjectSegment<'data> for PeSegment<'data, 'file> {
    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size)
    }

    fn data(&self) -> &'data [u8] {
        &self.file.data[self.section.pointer_to_raw_data as usize..]
            [..self.section.size_of_raw_data as usize]
    }

    #[inline]
    fn name(&self) -> Option<&str> {
        self.section.name().ok()
    }
}

impl<'data, 'file> Iterator for PeSectionIterator<'data, 'file> {
    type Item = PeSection<'data, 'file>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| PeSection {
            file: self.file,
            section,
        })
    }
}

impl<'data, 'file> ObjectSection<'data> for PeSection<'data, 'file> {
    #[inline]
    fn address(&self) -> u64 {
        u64::from(self.section.virtual_address)
    }

    #[inline]
    fn size(&self) -> u64 {
        u64::from(self.section.virtual_size)
    }

    fn data(&self) -> Cow<'data, [u8]> {
        Cow::from(
            &self.file.data[self.section.pointer_to_raw_data as usize..]
                [..self.section.size_of_raw_data as usize],
        )
    }

    fn name(&self) -> Option<&str> {
        self.section.name().ok()
    }

    #[inline]
    fn segment_name(&self) -> Option<&str> {
        None
    }

    #[inline]
    fn kind(&self) -> SectionKind {
        if self.section.characteristics
            & (pe::section_table::IMAGE_SCN_CNT_CODE | pe::section_table::IMAGE_SCN_MEM_EXECUTE)
            != 0
        {
            SectionKind::Text
        } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_INITIALIZED_DATA
            != 0
        {
            SectionKind::Data
        } else if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_UNINITIALIZED_DATA
            != 0
        {
            SectionKind::UninitializedData
        } else {
            SectionKind::Unknown
        }
    }
}

impl<'data, 'file> Iterator for PeSymbolIterator<'data, 'file> {
    type Item = Symbol<'data>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(export) = self.exports.next() {
            return Some(Symbol {
                kind: SymbolKind::Unknown,
                section_kind: Some(SectionKind::Unknown),
                global: true,
                name: export.name,
                address: export.rva as u64,
                size: 0,
            });
        }
        if let Some(import) = self.imports.next() {
            let name = match import.name {
                Cow::Borrowed(name) => Some(name),
                _ => None,
            };
            return Some(Symbol {
                kind: SymbolKind::Unknown,
                section_kind: None,
                global: true,
                name: name,
                address: 0,
                size: 0,
            });
        }
        None
    }
}
<|endoftext|>


<commit_before>//! Implements the extraction of the principal variation from the
//! transposition table.

use std::cmp::min;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Extracts the principal variation for a given position from the
/// transposition table.
///
/// The principal variation (PV) is the sequence of moves that the
/// engine considers best and therefore expects to be played.
pub fn extract_pv<T: HashTable, N: SearchNode>(tt: &T, position: &N) -> Variation {
    let mut p = position.clone();
    let mut our_turn = true;
    let mut moves = Vec::with_capacity(32);
    let mut root_value = VALUE_UNKNOWN;
    let mut value = VALUE_MAX;
    let mut bound = BOUND_UPPER;
    let mut depth = DEPTH_MAX + 1;

    'move_extraction: while let Some(e) = tt.probe(p.hash()) {
        depth = min(depth - 1, e.depth());

        if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
            // In half of the cases the value is from other side's perspective.
            if our_turn {
                value = e.value();
                bound = e.bound();
            } else {
                value = -e.value();
                bound = match e.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    b => b,
                };
            }
            assert!(value != VALUE_UNKNOWN);

            // Set the root value on the first iteration.
            if root_value == VALUE_UNKNOWN {
                root_value = value;
            }

            // Consider adding current entry's hash move to the
            // PV. There are 2 conditions for this:
            //
            // 1) The depth limit has not been reached yet.
            // 2) The value has not diverged from the root value.
            if depth > 0 &&
               match root_value {
                v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                v => v == value,
            } {
                // Verify that the hash move is legal.
                if let Some(m) = p.try_move_digest(e.move_digest()) {
                    if p.do_move(m) {
                        moves.push(m);

                        // Note: we stop expanding the PV on refutation moves.
                        if e.bound() == BOUND_EXACT {
                            our_turn = !our_turn;
                            continue 'move_extraction;
                        }
                    }
                }
            }
        }
        break 'move_extraction;
    }

    Variation {
        value: if root_value != VALUE_UNKNOWN {
            root_value
        } else {
            value
        },
        bound: bound,
        moves: moves,
    }
}
<commit_msg>fix comment<commit_after>//! Implements the extraction of the principal variation from the
//! transposition table.

use std::cmp::min;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Extracts the principal variation for a given position from the
/// transposition table.
///
/// The principal variation (PV) is the sequence of moves that the
/// engine considers best and therefore expects to be played.
pub fn extract_pv<T: HashTable, N: SearchNode>(tt: &T, position: &N) -> Variation {
    let mut p = position.clone();
    let mut our_turn = true;
    let mut moves = Vec::with_capacity(32);
    let mut root_value = VALUE_UNKNOWN;
    let mut value = VALUE_MAX;
    let mut bound = BOUND_UPPER;
    let mut depth = DEPTH_MAX + 1;

    'move_extraction: while let Some(e) = tt.probe(p.hash()) {
        depth = min(depth - 1, e.depth());

        if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
            // In half of the cases the value is from other side's perspective.
            if our_turn {
                value = e.value();
                bound = e.bound();
            } else {
                value = -e.value();
                bound = match e.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    b => b,
                };
            }
            assert!(value != VALUE_UNKNOWN);

            // Set the root value on the first iteration.
            if root_value == VALUE_UNKNOWN {
                root_value = value;
            }

            // Consider adding current entry's hash move to the
            // PV. There are 2 conditions for this:
            //
            // 1) The depth limit has not been reached yet.
            // 2) The value has not diverged from the root value.
            if depth > 0 &&
               match root_value {
                v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                v => v == value,
            } {
                // Verify that the hash move is legal.
                if let Some(m) = p.try_move_digest(e.move_digest()) {
                    if p.do_move(m) {
                        moves.push(m);

                        // Note: we continue expanding the PV only on best moves.
                        if e.bound() == BOUND_EXACT {
                            our_turn = !our_turn;
                            continue 'move_extraction;
                        }
                    }
                }
            }
        }
        break 'move_extraction;
    }

    Variation {
        value: if root_value != VALUE_UNKNOWN {
            root_value
        } else {
            value
        },
        bound: bound,
        moves: moves,
    }
}
<|endoftext|>