<commit_before>// Copyright 2015-2020 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(clippy::needless_doctest_main)]

//! The Resolver is responsible for performing recursive queries to lookup domain names.
//!
//! This is a 100% in process DNS resolver. It *does not* use the Host OS' resolver. If what is desired is to use the Host OS' resolver, generally in the system's libc, then the `std::net::ToSocketAddrs` variant over `&str` should be used.
//!
//! Unlike the `trust-dns-client`, this tries to provide a simpler interface to perform DNS queries. For update options, i.e. Dynamic DNS, the `trust-dns-client` crate must be used instead. The Resolver library is capable of searching multiple domains (this can be disabled by using an FQDN during lookup), dual-stack IPv4/IPv6 lookups, performing chained CNAME lookups, and features connection metric tracking for attempting to pick the best upstream DNS resolver.
//!
//! There are two types for performing DNS queries, [`Resolver`] and [`AsyncResolver`]. `Resolver` is the easiest to work with, it is a wrapper around [`AsyncResolver`]. `AsyncResolver` is a `Tokio` based async resolver, and can be used inside any `Tokio` based system.
//!
//! This as best as possible attempts to abide by the DNS RFCs, please file issues at https://github.com/bluejekyll/trust-dns .
//!
//! # Usage
//!
//! ## Declare dependency
//!
//! ```toml
//! [dependency]
//! async-std-resolver = "*"
//! ```
//!
//! ## Using the Tokio/Async Resolver
//!
//! For more advanced asynchronous usage, the `AsyncResolver`] is integrated with Tokio. In fact, the [`AsyncResolver`] is used by the synchronous Resolver for all lookups.
//!
//! ```rust
//! use std::net::*;
//! use async_std::prelude::*;
//! use async_std_resolver::{resolver, config};
//!
//! #[async_std::main]
//! async fn main() {
//!   // Construct a new Resolver with default configuration options
//!   let resolver = resolver(
//!     config::ResolverConfig::default(),
//!     config::ResolverOpts::default(),
//!   ).await.expect("failed to connect resolver");
//!
//!   // Lookup the IP addresses associated with a name.
//!   // This returns a future that will lookup the IP addresses, it must be run in the Core to
//!   //  to get the actual result.
//!   let mut response = resolver.lookup_ip("www.example.com.").await.unwrap();
//!
//!   // There can be many addresses associated with the name,
//!   //  this can return IPv4 and/or IPv6 addresses
//!   let address = response.iter().next().expect("no addresses returned!");
//!   if address.is_ipv4() {
//!     assert_eq!(address, IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)));
//!   } else {
//!     assert_eq!(address, IpAddr::V6(Ipv6Addr::new(0x2606, 0x2800, 0x220, 0x1, 0x248, 0x1893, 0x25c8, 0x1946)));
//!   }
//! }
//! ```
//!
//! ## Using the host system config
//!
//! On Unix systems, the `/etc/resolv.conf` can be used for configuration. Not all options specified in the host systems `resolv.conf` are applicable or compatible with this software. In addition there may be additional options supported which the host system does not. Example:
//!
//! ```
//! use std::net::*;
//! use async_std::prelude::*;
//! use async_std_resolver::{resolver_from_system_conf, config};
//!
//! #[async_std::main]
//! async fn main() {
//!   // Use the host OS'es `/etc/resolv.conf`
//!   # #[cfg(unix)]
//!   let resolver = resolver_from_system_conf().await.unwrap();
//!   # #[cfg(unix)]
//!   let response = resolver.lookup_ip("www.example.com.").await.unwrap();
//! }
//! ```

use trust_dns_resolver::AsyncResolver;

use crate::runtime::AsyncStdConnection;
use crate::runtime::AsyncStdConnectionProvider;
use crate::runtime::AsyncStdRuntimeHandle;

mod net;
mod runtime;
#[cfg(test)]
mod tests;
mod time;

pub use trust_dns_resolver::config;
pub use trust_dns_resolver::error::ResolveError;
pub use trust_dns_resolver::lookup;
pub use trust_dns_resolver::lookup_ip;
pub use trust_dns_resolver::proto;

/// An AsyncResolver used with async_std
pub type AsyncStdResolver = AsyncResolver<AsyncStdConnection, AsyncStdConnectionProvider>;

/// Construct a new async-std based `AsyncResolver` with the provided configuration.
///
/// # Arguments
///
/// * `config` - configuration, name_servers, etc. for the Resolver
/// * `options` - basic lookup options for the resolver
///
/// # Returns
///
/// A tuple containing the new `AsyncResolver` and a future that drives the
/// background task that runs resolutions for the `AsyncResolver`. See the
/// documentation for `AsyncResolver` for more information on how to use
/// the background future.
pub async fn resolver(
    config: config::ResolverConfig,
    options: config::ResolverOpts,
) -> Result<AsyncStdResolver, ResolveError> {
    AsyncStdResolver::new(config, options, AsyncStdRuntimeHandle).await
}

/// Constructs a new async-std based Resolver with the system configuration.
///
/// This will use `/etc/resolv.conf` on Unix OSes and the registry on Windows.
#[cfg(any(unix, target_os = "windows"))]
#[cfg(feature = "system-config")]
pub async fn resolver_from_system_conf() -> Result<AsyncStdResolver, ResolveError> {
    AsyncStdResolver::from_system_conf(AsyncStdRuntimeHandle).await
}
<commit_msg>fix readme documentation for async-std, remove tokio references<commit_after>// Copyright 2015-2020 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(clippy::needless_doctest_main)]

//! The Resolver is responsible for performing recursive queries to lookup domain names.
//!
//! This is a 100% in process DNS resolver. It *does not* use the Host OS' resolver. If what is desired is to use the Host OS' resolver, generally in the system's libc, then the `std::net::ToSocketAddrs` variant over `&str` should be used.
//!
//! Unlike the `trust-dns-client`, this tries to provide a simpler interface to perform DNS queries. For update options, i.e. Dynamic DNS, the `trust-dns-client` crate must be used instead. The Resolver library is capable of searching multiple domains (this can be disabled by using an FQDN during lookup), dual-stack IPv4/IPv6 lookups, performing chained CNAME lookups, and features connection metric tracking for attempting to pick the best upstream DNS resolver.
//!
//! There are two types for performing DNS queries, [`Resolver`] and [`AsyncResolver`]. `Resolver` is the easiest to work with, it is a wrapper around [`AsyncResolver`]. `AsyncResolver` is a `async-std` based async resolver, and can be used inside any `asyn-std` based system.
//!
//! This as best as possible attempts to abide by the DNS RFCs, please file issues at https://github.com/bluejekyll/trust-dns .
//!
//! # Usage
//!
//! ## Declare dependency
//!
//! ```toml
//! [dependency]
//! async-std-resolver = "*"
//! ```
//!
//! ## Using the async-std Resolver
//!
//! For more advanced asynchronous usage, the [`AsyncResolver`] is integrated with async-std.
//!
//! ```rust
//! use std::net::*;
//! use async_std::prelude::*;
//! use async_std_resolver::{resolver, config};
//!
//! #[async_std::main]
//! async fn main() {
//!   // Construct a new Resolver with default configuration options
//!   let resolver = resolver(
//!     config::ResolverConfig::default(),
//!     config::ResolverOpts::default(),
//!   ).await.expect("failed to connect resolver");
//!
//!   // Lookup the IP addresses associated with a name.
//!   // This returns a future that will lookup the IP addresses, it must be run in the Core to
//!   //  to get the actual result.
//!   let mut response = resolver.lookup_ip("www.example.com.").await.unwrap();
//!
//!   // There can be many addresses associated with the name,
//!   //  this can return IPv4 and/or IPv6 addresses
//!   let address = response.iter().next().expect("no addresses returned!");
//!   if address.is_ipv4() {
//!     assert_eq!(address, IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)));
//!   } else {
//!     assert_eq!(address, IpAddr::V6(Ipv6Addr::new(0x2606, 0x2800, 0x220, 0x1, 0x248, 0x1893, 0x25c8, 0x1946)));
//!   }
//! }
//! ```
//!
//! ## Using the host system config
//!
//! On Unix systems, the `/etc/resolv.conf` can be used for configuration. Not all options specified in the host systems `resolv.conf` are applicable or compatible with this software. In addition there may be additional options supported which the host system does not. Example:
//!
//! ```
//! use std::net::*;
//! use async_std::prelude::*;
//! use async_std_resolver::{resolver_from_system_conf, config};
//!
//! #[async_std::main]
//! async fn main() {
//!   // Use the host OS'es `/etc/resolv.conf`
//!   # #[cfg(unix)]
//!   let resolver = resolver_from_system_conf().await.unwrap();
//!   # #[cfg(unix)]
//!   let response = resolver.lookup_ip("www.example.com.").await.unwrap();
//! }
//! ```

use trust_dns_resolver::AsyncResolver;

use crate::runtime::AsyncStdConnection;
use crate::runtime::AsyncStdConnectionProvider;
use crate::runtime::AsyncStdRuntimeHandle;

mod net;
mod runtime;
#[cfg(test)]
mod tests;
mod time;

pub use trust_dns_resolver::config;
pub use trust_dns_resolver::error::ResolveError;
pub use trust_dns_resolver::lookup;
pub use trust_dns_resolver::lookup_ip;
pub use trust_dns_resolver::proto;

/// An AsyncResolver used with async_std
pub type AsyncStdResolver = AsyncResolver<AsyncStdConnection, AsyncStdConnectionProvider>;

/// Construct a new async-std based `AsyncResolver` with the provided configuration.
///
/// # Arguments
///
/// * `config` - configuration, name_servers, etc. for the Resolver
/// * `options` - basic lookup options for the resolver
///
/// # Returns
///
/// A tuple containing the new `AsyncResolver` and a future that drives the
/// background task that runs resolutions for the `AsyncResolver`. See the
/// documentation for `AsyncResolver` for more information on how to use
/// the background future.
pub async fn resolver(
    config: config::ResolverConfig,
    options: config::ResolverOpts,
) -> Result<AsyncStdResolver, ResolveError> {
    AsyncStdResolver::new(config, options, AsyncStdRuntimeHandle).await
}

/// Constructs a new async-std based Resolver with the system configuration.
///
/// This will use `/etc/resolv.conf` on Unix OSes and the registry on Windows.
#[cfg(any(unix, target_os = "windows"))]
#[cfg(feature = "system-config")]
pub async fn resolver_from_system_conf() -> Result<AsyncStdResolver, ResolveError> {
    AsyncStdResolver::from_system_conf(AsyncStdRuntimeHandle).await
}
<|endoftext|>


<commit_before>use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::File;
use std::io::{prelude::*, BufReader};
use std::path::PathBuf;
use std::str::FromStr;

use bls::blst_implementations::PublicKeyBytes;
use types::{graffiti::GraffitiString, Graffiti};

#[derive(Debug)]
pub enum Error {
    InvalidFile(std::io::Error),
    InvalidLine(String),
    InvalidPublicKey(String),
    InvalidGraffiti(String),
}

/// Struct to load validator graffitis from file.
/// The graffiti file is expected to have the following structure
///
/// default: Lighthouse
/// public_key1: graffiti1
/// public_key2: graffiti2
/// ...
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraffitiFile {
    graffiti_path: PathBuf,
    graffitis: HashMap<PublicKeyBytes, Graffiti>,
    default: Option<Graffiti>,
}

impl GraffitiFile {
    pub fn new(graffiti_path: PathBuf) -> Self {
        Self {
            graffiti_path,
            graffitis: HashMap::new(),
            default: None,
        }
    }

    /// Loads the graffiti file and populates the default graffiti and `graffitis` hashmap.
    /// Returns the graffiti corresponding to the given public key if present, else returns the
    /// default graffiti.
    ///
    /// Returns an error if loading from the graffiti file fails.
    pub fn load_graffiti(
        &mut self,
        public_key: &PublicKeyBytes,
    ) -> Result<Option<Graffiti>, Error> {
        self.read_graffiti_file()?;
        Ok(self.graffitis.get(public_key).copied().or(self.default))
    }

    /// Reads from a graffiti file with the specified format and populates the default value
    /// and the hashmap.
    ///
    /// Returns an error if the file does not exist, or if the format is invalid.
    pub fn read_graffiti_file(&mut self) -> Result<(), Error> {
        let file = File::open(self.graffiti_path.as_path()).map_err(Error::InvalidFile)?;
        let reader = BufReader::new(file);

        let lines = reader.lines();

        for line in lines {
            let line = line.map_err(|e| Error::InvalidLine(e.to_string()))?;
            let (pk_opt, graffiti) = read_line(&line)?;
            match pk_opt {
                Some(pk) => {
                    self.graffitis.insert(pk, graffiti);
                }
                None => self.default = Some(graffiti),
            }
        }
        Ok(())
    }
}

/// Parses a line from the graffiti file.
///
/// `Ok((None, graffiti))` represents the graffiti for the default key.
/// `Ok((Some(pk), graffiti))` represents graffiti for the public key `pk`.
/// Returns an error if the line is in the wrong format or does not contain a valid public key or graffiti.
fn read_line(line: &str) -> Result<(Option<PublicKeyBytes>, Graffiti), Error> {
    if let Some(i) = line.find(':') {
        let (key, value) = line.split_at(i);
        // Note: `value.len() >=1` so `value[1..]` is safe
        let graffiti = GraffitiString::from_str(value[1..].trim())
            .map_err(Error::InvalidGraffiti)?
            .into();
        if key == "default" {
            Ok((None, graffiti))
        } else {
            let pk = PublicKeyBytes::from_str(&key).map_err(Error::InvalidPublicKey)?;
            Ok((Some(pk), graffiti))
        }
    } else {
        Err(Error::InvalidLine(format!("Missing delimiter: {}", line)))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use bls::Keypair;
    use std::io::LineWriter;
    use tempfile::TempDir;

    const DEFAULT_GRAFFITI: &str = "lighthouse";
    const CUSTOM_GRAFFITI1: &str = "custom-graffiti1";
    const CUSTOM_GRAFFITI2: &str = "graffitiwall:720:641:#ffff00";
    const EMPTY_GRAFFITI: &str = "";
    const PK1: &str = "0x800012708dc03f611751aad7a43a082142832b5c1aceed07ff9b543cf836381861352aa923c70eeb02018b638aa306aa";
    const PK2: &str = "0x80001866ce324de7d80ec73be15e2d064dcf121adf1b34a0d679f2b9ecbab40ce021e03bb877e1a2fe72eaaf475e6e21";
    const PK3: &str = "0x9035d41a8bc11b08c17d0d93d876087958c9d055afe86fce558e3b988d92434769c8d50b0b463708db80c6aae1160c02";

    // Create a graffiti file in the required format and return a path to the file.
    fn create_graffiti_file() -> PathBuf {
        let temp = TempDir::new().unwrap();
        let pk1 = PublicKeyBytes::deserialize(&hex::decode(&PK1[2..]).unwrap()).unwrap();
        let pk2 = PublicKeyBytes::deserialize(&hex::decode(&PK2[2..]).unwrap()).unwrap();
        let pk3 = PublicKeyBytes::deserialize(&hex::decode(&PK3[2..]).unwrap()).unwrap();

        let file_name = temp.into_path().join("graffiti.txt");

        let file = File::create(&file_name).unwrap();
        let mut graffiti_file = LineWriter::new(file);
        graffiti_file
            .write_all(format!("default: {}\n", DEFAULT_GRAFFITI).as_bytes())
            .unwrap();
        graffiti_file
            .write_all(format!("{}: {}\n", pk1.to_hex_string(), CUSTOM_GRAFFITI1).as_bytes())
            .unwrap();
        graffiti_file
            .write_all(format!("{}: {}\n", pk2.to_hex_string(), CUSTOM_GRAFFITI2).as_bytes())
            .unwrap();
        graffiti_file
            .write_all(format!("{}:{}\n", pk3.to_hex_string(), EMPTY_GRAFFITI).as_bytes())
            .unwrap();
        graffiti_file.flush().unwrap();
        file_name
    }

    #[test]
    fn test_load_graffiti() {
        let graffiti_file_path = create_graffiti_file();
        let mut gf = GraffitiFile::new(graffiti_file_path);

        let pk1 = PublicKeyBytes::deserialize(&hex::decode(&PK1[2..]).unwrap()).unwrap();
        let pk2 = PublicKeyBytes::deserialize(&hex::decode(&PK2[2..]).unwrap()).unwrap();
        let pk3 = PublicKeyBytes::deserialize(&hex::decode(&PK3[2..]).unwrap()).unwrap();

        // Read once
        gf.read_graffiti_file().unwrap();

        assert_eq!(
            gf.load_graffiti(&pk1).unwrap().unwrap(),
            GraffitiString::from_str(CUSTOM_GRAFFITI1).unwrap().into()
        );
        assert_eq!(
            gf.load_graffiti(&pk2).unwrap().unwrap(),
            GraffitiString::from_str(CUSTOM_GRAFFITI2).unwrap().into()
        );

        assert_eq!(
            gf.load_graffiti(&pk3).unwrap().unwrap(),
            GraffitiString::from_str(EMPTY_GRAFFITI).unwrap().into()
        );

        // Random pk should return the default graffiti
        let random_pk = Keypair::random().pk.compress();
        assert_eq!(
            gf.load_graffiti(&random_pk).unwrap().unwrap(),
            GraffitiString::from_str(DEFAULT_GRAFFITI).unwrap().into()
        );
    }
}
<commit_msg>Use generic BLS object instead of BLST (#2290)<commit_after>use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::File;
use std::io::{prelude::*, BufReader};
use std::path::PathBuf;
use std::str::FromStr;

use bls::PublicKeyBytes;
use types::{graffiti::GraffitiString, Graffiti};

#[derive(Debug)]
pub enum Error {
    InvalidFile(std::io::Error),
    InvalidLine(String),
    InvalidPublicKey(String),
    InvalidGraffiti(String),
}

/// Struct to load validator graffitis from file.
/// The graffiti file is expected to have the following structure
///
/// default: Lighthouse
/// public_key1: graffiti1
/// public_key2: graffiti2
/// ...
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraffitiFile {
    graffiti_path: PathBuf,
    graffitis: HashMap<PublicKeyBytes, Graffiti>,
    default: Option<Graffiti>,
}

impl GraffitiFile {
    pub fn new(graffiti_path: PathBuf) -> Self {
        Self {
            graffiti_path,
            graffitis: HashMap::new(),
            default: None,
        }
    }

    /// Loads the graffiti file and populates the default graffiti and `graffitis` hashmap.
    /// Returns the graffiti corresponding to the given public key if present, else returns the
    /// default graffiti.
    ///
    /// Returns an error if loading from the graffiti file fails.
    pub fn load_graffiti(
        &mut self,
        public_key: &PublicKeyBytes,
    ) -> Result<Option<Graffiti>, Error> {
        self.read_graffiti_file()?;
        Ok(self.graffitis.get(public_key).copied().or(self.default))
    }

    /// Reads from a graffiti file with the specified format and populates the default value
    /// and the hashmap.
    ///
    /// Returns an error if the file does not exist, or if the format is invalid.
    pub fn read_graffiti_file(&mut self) -> Result<(), Error> {
        let file = File::open(self.graffiti_path.as_path()).map_err(Error::InvalidFile)?;
        let reader = BufReader::new(file);

        let lines = reader.lines();

        for line in lines {
            let line = line.map_err(|e| Error::InvalidLine(e.to_string()))?;
            let (pk_opt, graffiti) = read_line(&line)?;
            match pk_opt {
                Some(pk) => {
                    self.graffitis.insert(pk, graffiti);
                }
                None => self.default = Some(graffiti),
            }
        }
        Ok(())
    }
}

/// Parses a line from the graffiti file.
///
/// `Ok((None, graffiti))` represents the graffiti for the default key.
/// `Ok((Some(pk), graffiti))` represents graffiti for the public key `pk`.
/// Returns an error if the line is in the wrong format or does not contain a valid public key or graffiti.
fn read_line(line: &str) -> Result<(Option<PublicKeyBytes>, Graffiti), Error> {
    if let Some(i) = line.find(':') {
        let (key, value) = line.split_at(i);
        // Note: `value.len() >=1` so `value[1..]` is safe
        let graffiti = GraffitiString::from_str(value[1..].trim())
            .map_err(Error::InvalidGraffiti)?
            .into();
        if key == "default" {
            Ok((None, graffiti))
        } else {
            let pk = PublicKeyBytes::from_str(&key).map_err(Error::InvalidPublicKey)?;
            Ok((Some(pk), graffiti))
        }
    } else {
        Err(Error::InvalidLine(format!("Missing delimiter: {}", line)))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use bls::Keypair;
    use std::io::LineWriter;
    use tempfile::TempDir;

    const DEFAULT_GRAFFITI: &str = "lighthouse";
    const CUSTOM_GRAFFITI1: &str = "custom-graffiti1";
    const CUSTOM_GRAFFITI2: &str = "graffitiwall:720:641:#ffff00";
    const EMPTY_GRAFFITI: &str = "";
    const PK1: &str = "0x800012708dc03f611751aad7a43a082142832b5c1aceed07ff9b543cf836381861352aa923c70eeb02018b638aa306aa";
    const PK2: &str = "0x80001866ce324de7d80ec73be15e2d064dcf121adf1b34a0d679f2b9ecbab40ce021e03bb877e1a2fe72eaaf475e6e21";
    const PK3: &str = "0x9035d41a8bc11b08c17d0d93d876087958c9d055afe86fce558e3b988d92434769c8d50b0b463708db80c6aae1160c02";

    // Create a graffiti file in the required format and return a path to the file.
    fn create_graffiti_file() -> PathBuf {
        let temp = TempDir::new().unwrap();
        let pk1 = PublicKeyBytes::deserialize(&hex::decode(&PK1[2..]).unwrap()).unwrap();
        let pk2 = PublicKeyBytes::deserialize(&hex::decode(&PK2[2..]).unwrap()).unwrap();
        let pk3 = PublicKeyBytes::deserialize(&hex::decode(&PK3[2..]).unwrap()).unwrap();

        let file_name = temp.into_path().join("graffiti.txt");

        let file = File::create(&file_name).unwrap();
        let mut graffiti_file = LineWriter::new(file);
        graffiti_file
            .write_all(format!("default: {}\n", DEFAULT_GRAFFITI).as_bytes())
            .unwrap();
        graffiti_file
            .write_all(format!("{}: {}\n", pk1.to_hex_string(), CUSTOM_GRAFFITI1).as_bytes())
            .unwrap();
        graffiti_file
            .write_all(format!("{}: {}\n", pk2.to_hex_string(), CUSTOM_GRAFFITI2).as_bytes())
            .unwrap();
        graffiti_file
            .write_all(format!("{}:{}\n", pk3.to_hex_string(), EMPTY_GRAFFITI).as_bytes())
            .unwrap();
        graffiti_file.flush().unwrap();
        file_name
    }

    #[test]
    fn test_load_graffiti() {
        let graffiti_file_path = create_graffiti_file();
        let mut gf = GraffitiFile::new(graffiti_file_path);

        let pk1 = PublicKeyBytes::deserialize(&hex::decode(&PK1[2..]).unwrap()).unwrap();
        let pk2 = PublicKeyBytes::deserialize(&hex::decode(&PK2[2..]).unwrap()).unwrap();
        let pk3 = PublicKeyBytes::deserialize(&hex::decode(&PK3[2..]).unwrap()).unwrap();

        // Read once
        gf.read_graffiti_file().unwrap();

        assert_eq!(
            gf.load_graffiti(&pk1).unwrap().unwrap(),
            GraffitiString::from_str(CUSTOM_GRAFFITI1).unwrap().into()
        );
        assert_eq!(
            gf.load_graffiti(&pk2).unwrap().unwrap(),
            GraffitiString::from_str(CUSTOM_GRAFFITI2).unwrap().into()
        );

        assert_eq!(
            gf.load_graffiti(&pk3).unwrap().unwrap(),
            GraffitiString::from_str(EMPTY_GRAFFITI).unwrap().into()
        );

        // Random pk should return the default graffiti
        let random_pk = Keypair::random().pk.compress();
        assert_eq!(
            gf.load_graffiti(&random_pk).unwrap().unwrap(),
            GraffitiString::from_str(DEFAULT_GRAFFITI).unwrap().into()
        );
    }
}
<|endoftext|>


<commit_before>mod cgb;
mod palette;

use super::cpu::CycleType;
use super::memory::Memory;
use super::irq::{Interrupt, IrqHandler};

use self::GpuMode::*;
use self::palette::{PaletteClassic, PaletteGrayShade};

/// The width of the Game Boy's screen, in pixels.
pub const SCREEN_W: usize = 160;
/// The height of the Game Boy's screen, in pixels.
pub const SCREEN_H: usize = 144;

const TILEMAP_SIZE: usize = 0x400;

/// Simple RGB color representation.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct RGB {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl RGB {
    pub fn new(r: u8, g: u8, b: u8) -> RGB {
        RGB { r: r, g: g, b: b }
    }
}

/// Type defining the state of a Game Boy (Color) screen, each pixel being
/// fully defined by its RGB color.
pub type ScreenData = [RGB; SCREEN_W * SCREEN_H];

/// A tile is an area of 8x8 pixels.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct Tile {
    /// Each tile occupies 16 bytes, where 2 bytes represent a line:
    /// byte 0-1 = first line (upper 8 pixels)
    /// byte 2-3 = second lines
    /// etc.
    /// For each line, the first byte defines the bit 0 of the color numbers
    /// and the second byte defines the bit 1. In both cases, bit 7 is the
    /// leftmost pixel and bit 0 the rightmost.
    /// Each pixel thus has a color number from 0 to 3 wich is translated into
    /// colors or shades of gray according to the current palettes.
    raw_data: [u8; 16],
    /// Cached internal state better suited for rendering.
    data: [[u8; 8]; 8],
}

impl Tile {
    pub fn new(raw_data: [u8; 16]) -> Tile {
        let mut new_tile = Tile {
            raw_data: raw_data,
            data: [[0x00; 8]; 8],
        };
        new_tile.update();
        new_tile
    }

    /// Update the tile's internal state to match its raw value.
    pub fn update(&mut self) {
        for y in 0..8 {
            let line_lo = self.raw_data[y * 2];
            let line_hi = self.raw_data[y * 2 + 1];
            for x in 0..8 {
                let color = ((line_hi >> (7 - x)) & 0x01) << 1 | ((line_lo >> (7 - x)) & 0x01);
                debug_assert!(color < 4);
                self.data[y][x] = color;
            }
        }
    }

    pub fn data(&self) -> &[[u8; 8]; 8] {
        &self.data
    }
    pub fn data_mut(&mut self) -> &mut [[u8; 8]; 8] {
        &mut self.data
    }
}

/// The different modes a GPU can spend its time in.
#[allow(non_camel_case_types)]
enum GpuMode {
    H_Blank = 0,
    V_Blank = 1,
    OAM_Read = 2,
    VRAM_Read = 3,
}

/// The GPU registers' addresses.
mod regs {
    pub const STAT: usize = 0xFF41;
    pub const SCY: usize = 0xFF42;
    pub const SCX: usize = 0xFF43;
    pub const LY: usize = 0xFF44; // read-only
    pub const LYC: usize = 0xFF45;
    pub const BGP: usize = 0xFF47; // ignored in CGB mode
    pub const OBP_0: usize = 0xFF48; // ignored in CGB mode
    pub const OBP_1: usize = 0xFF49; // ignored in CGB mode
    pub const WY: usize = 0xFF4A;
    pub const WX: usize = 0xFF4B;
}

/// The structure holding and emulating the GPU state.
///
/// Time durations are expressed in CPU clock cycles with a CPU clock speed of
/// 4194304 Hz.
pub struct Gpu {
    /// If true, a Game Boy Color GPU will be emulated.
    cgb_mode: bool,
    /// CGB-specific data, needed in CGB mode.
    cgb_data: Option<cgb::GpuData>,
    /// The current mode.
    mode: GpuMode,
    /// The number of cycles spent in the current mode.
    mode_clock: CycleType,
    /// The index of the current scanline.
    /// Can take any value between 0 and 153, with values between 144 and 153
    /// indicating a V-Blank period.
    /// Writing to the LY register resets it to 0.
    ly: usize,
    /// Horizontal position of the top-left corner of the on-screen background.
    scroll_x: u8,
    /// Vertical position of the top-left corner of the on-screen background.
    scroll_y: u8,
    // Horizontal position of the top-left of the Window area.
    window_x: u8,
    // Vertical position of the top-left of the Window area.
    window_y: u8,
    /// The frame buffer containing the display's pixels.
    frame_buffer: ScreenData,
    /// The background palette, assigning gray shades to the color numbers
    /// of the background and window tiles.
    /// Not used in CGB mode (yet 'Option' is not used for convenience).
    bg_palette: PaletteClassic,
    /// The two object palettes (Classic mode only), assigning gray shades to
    /// the color numbers of the sprites. Color 0 is not used (transparent).
    /// Not used in CGB mode.
    ob_palettes: [PaletteClassic; 2],
    /// The tileset in VRAM.
    tileset: [Tile; 384],
    /// The two tilemaps in VRAM.
    tilemaps: [[u8; TILEMAP_SIZE]; 2],
    /// Should the screen be redrawn by the frontend ?
    /// Must be externally set to false after that.
    pub dirty: bool,
}

impl Gpu {
    /// Create and return a new 'Gpu' instance.
    pub fn new(cgb_mode: bool) -> Gpu {
        Gpu {
            cgb_mode,
            cgb_data: if cgb_mode {
                Some(cgb::GpuData::new())
            } else {
                None
            },
            mode: H_Blank,
            mode_clock: 0,
            ly: 0,
            scroll_x: 0,
            scroll_y: 0,
            window_x: 0,
            window_y: 0,
            frame_buffer: [RGB::new(255, 255, 255); SCREEN_W * SCREEN_H],
            bg_palette: PaletteClassic::new(),
            ob_palettes: [PaletteClassic::new(); 2],
            tileset: [Tile::new([0x00; 16]); 384],
            tilemaps: [[0x00; TILEMAP_SIZE]; 2],
            dirty: false,
        }
    }

    /// Advance the GPU simulation.
    pub fn step(&mut self, ticks: CycleType, irq_handler: &mut IrqHandler) {
        self.mode_clock += ticks;

        match self.mode {
            // scanline, accessing OAM
            OAM_Read => {
                if self.mode_clock >= 80 {
                    self.switch_mode(VRAM_Read)
                }
            }
            // scanline, accessing VRAM
            VRAM_Read => {
                if self.mode_clock >= 172 {
                    // end of scanline
                    self.switch_mode(H_Blank);
                    self.render_scanline();
                    // TODO : throw LCD_Stat interrupt here ?
                }
            }
            // horizontal blank
            H_Blank => {
                if self.mode_clock >= 204 {
                    self.ly += 1;
                    if self.ly == SCREEN_H {
                        self.switch_mode(V_Blank);
                        self.dirty = true; // the framebuffer can be rendered
                        irq_handler.request_interrupt(Interrupt::V_Blank);
                    } else {
                        self.switch_mode(OAM_Read);
                    }
                }
            }
            // vertical blank (10 lines)
            V_Blank => {
                if self.mode_clock >= 456 {
                    self.mode_clock = 0;
                    self.ly += 1;
                    if self.ly == SCREEN_H + 10 {
                        self.switch_mode(OAM_Read);
                        self.ly = 0;
                    }
                }
            }
        }
    }

    /// Switch the current GPU mode.
    fn switch_mode(&mut self, new_mode: GpuMode) {
        self.mode_clock = 0;
        self.mode = new_mode;
    }

    /// Write the current scanline in the framebuffer.
    fn render_scanline(&mut self) {}
}

impl Memory for Gpu {
    fn read_byte(&mut self, address: u16) -> u8 {
        use self::regs::*;
        use self::cgb::regs as r;

        let a = address as usize;

        if self.cgb_mode {
            let data = self.cgb_data.as_ref().unwrap();
            match a {
                r::VRAM_BANK => return data.vram_bank_selector,
                r::BGP_INDEX => return data.bg_palette_index.raw_value(),
                r::BGP_DATA => return data.get_bg_color(),
                r::OBP_INDEX => return data.ob_palette_index.raw_value(),
                r::OBP_DATA => return data.get_ob_color(),
                _ => {}
            }
        }
        match a {
            0x8000...0x9FFF => {
                // Video RAM
                let bank_address = a & 0x1FFF;
                if self.cgb_mode {
                    let data = self.cgb_data.as_ref().unwrap();
                    if data.vram_bank_selector & 0x01 == 0x01 {
                        // return data.vram_bank[bank_address];
                    }
                }
                // return self.vram_bank[bank_address];
                0
            }
            SCY => self.scroll_y,
            SCX => self.scroll_x,
            LY => self.ly as u8,
            BGP => self.bg_palette.raw(),
            OBP_0 => self.ob_palettes[0].raw(),
            OBP_1 => self.ob_palettes[1].raw(),
            WY => self.window_y,
            WX => self.window_x,
            _ => 0,
        }
    }
    fn write_byte(&mut self, address: u16, byte: u8) {
        use self::regs::*;
        use self::cgb::regs as r;

        let a = address as usize;

        if self.cgb_mode {
            let data = self.cgb_data.as_mut().unwrap();
            let mut done = true;
            match a {
                r::VRAM_BANK => data.vram_bank_selector = byte,
                r::BGP_INDEX => data.bg_palette_index.update_with(byte),
                r::BGP_DATA => data.set_bg_color(byte),
                r::OBP_INDEX => data.ob_palette_index.update_with(byte),
                r::OBP_DATA => data.set_ob_color(byte),
                _ => {
                    done = false;
                }
            }
            if done {
                return;
            }
        }
        match a {
            0x8000...0x9FFF => {
                // Video RAM
                let bank_address = a & 0x1FFF;
                if self.cgb_mode {
                    let data = self.cgb_data.as_mut().unwrap();
                    if data.vram_bank_selector & 0x01 == 0x01 {
                        // data.vram_bank[bank_address] = byte;
                    }
                }
                // self.vram_bank[bank_address] = byte;
            }
            SCY => self.scroll_y = byte,
            SCX => self.scroll_x = byte,
            LY => self.ly = 0,
            BGP => self.bg_palette.set(byte),
            OBP_0 => self.ob_palettes[0].set(byte),
            OBP_1 => self.ob_palettes[1].set(byte),
            WY => self.window_y = byte,
            WX => self.window_x = byte,
            _ => (),
        }
    }
}

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

    #[test]
    fn test_tile_update() {
        // Source for the Tile example: http://fms.komkon.org/GameBoy/Tech/Software.html
        // .33333..                          .33333.. -> 0b0111_1100 -> 0x7C
        // 22...22.                                      0b0111_1100 -> 0x7C
        // 11...11.                          22...22. -> 0b0000_0000 -> 0x00
        // 2222222.                                      0b1100_0110 -> 0xC6
        // 33...33.                          11...11. -> 0b1100_0110 -> 0xC6
        // 22...22.                                      0b0000_0000 -> 0x00
        // 11...11.                          2222222. -> 0b0000_0000 -> 0x00
        // ........                                      0b1111_1110 -> 0xFE
        // 33...33. -> 0b1100_0110 -> 0xC6
        // 0b1100_0110 -> 0xC6
        // 22...22. -> 0b0000_0000 -> 0x00
        // 0b1100_0110 -> 0xC6
        // 11...11. -> 0b1100_0110 -> 0xC6
        // 0b0000_0000 -> 0x00
        // ........ -> 0b0000_0000 -> 0x00
        // 0b0000_0000 -> 0x00
        //
        let tile = Tile::new([
            0x7C, 0x7C, 0x00, 0xC6, 0xC6, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0x00,
            0x00, 0x00,
        ]);
        let data = tile.data();
        let data_test = [
            [0, 3, 3, 3, 3, 3, 0, 0],
            [2, 2, 0, 0, 0, 2, 2, 0],
            [1, 1, 0, 0, 0, 1, 1, 0],
            [2, 2, 2, 2, 2, 2, 2, 0],
            [3, 3, 0, 0, 0, 3, 3, 0],
            [2, 2, 0, 0, 0, 2, 2, 0],
            [1, 1, 0, 0, 0, 1, 1, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
        ];
        for (y, line) in data.iter().enumerate() {
            for (x, color_value) in line.iter().enumerate() {
                assert_eq!(*color_value, data_test[y][x]);
            }
        }
    }
}
<commit_msg>Syntactic sugarfor gpu::RGB struct creation<commit_after>mod cgb;
mod palette;

use super::cpu::CycleType;
use super::memory::Memory;
use super::irq::{Interrupt, IrqHandler};

use self::GpuMode::*;
use self::palette::{PaletteClassic, PaletteGrayShade};

/// The width of the Game Boy's screen, in pixels.
pub const SCREEN_W: usize = 160;
/// The height of the Game Boy's screen, in pixels.
pub const SCREEN_H: usize = 144;

const TILEMAP_SIZE: usize = 0x400;

/// Simple RGB color representation.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct RGB {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl RGB {
    pub fn new(r: u8, g: u8, b: u8) -> RGB {
        RGB { r, g, b }
    }
}

/// Type defining the state of a Game Boy (Color) screen, each pixel being
/// fully defined by its RGB color.
pub type ScreenData = [RGB; SCREEN_W * SCREEN_H];

/// A tile is an area of 8x8 pixels.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct Tile {
    /// Each tile occupies 16 bytes, where 2 bytes represent a line:
    /// byte 0-1 = first line (upper 8 pixels)
    /// byte 2-3 = second lines
    /// etc.
    /// For each line, the first byte defines the bit 0 of the color numbers
    /// and the second byte defines the bit 1. In both cases, bit 7 is the
    /// leftmost pixel and bit 0 the rightmost.
    /// Each pixel thus has a color number from 0 to 3 wich is translated into
    /// colors or shades of gray according to the current palettes.
    raw_data: [u8; 16],
    /// Cached internal state better suited for rendering.
    data: [[u8; 8]; 8],
}

impl Tile {
    pub fn new(raw_data: [u8; 16]) -> Tile {
        let mut new_tile = Tile {
            raw_data: raw_data,
            data: [[0x00; 8]; 8],
        };
        new_tile.update();
        new_tile
    }

    /// Update the tile's internal state to match its raw value.
    pub fn update(&mut self) {
        for y in 0..8 {
            let line_lo = self.raw_data[y * 2];
            let line_hi = self.raw_data[y * 2 + 1];
            for x in 0..8 {
                let color = ((line_hi >> (7 - x)) & 0x01) << 1 | ((line_lo >> (7 - x)) & 0x01);
                debug_assert!(color < 4);
                self.data[y][x] = color;
            }
        }
    }

    pub fn data(&self) -> &[[u8; 8]; 8] {
        &self.data
    }
    pub fn data_mut(&mut self) -> &mut [[u8; 8]; 8] {
        &mut self.data
    }
}

/// The different modes a GPU can spend its time in.
#[allow(non_camel_case_types)]
enum GpuMode {
    H_Blank = 0,
    V_Blank = 1,
    OAM_Read = 2,
    VRAM_Read = 3,
}

/// The GPU registers' addresses.
mod regs {
    pub const STAT: usize = 0xFF41;
    pub const SCY: usize = 0xFF42;
    pub const SCX: usize = 0xFF43;
    pub const LY: usize = 0xFF44; // read-only
    pub const LYC: usize = 0xFF45;
    pub const BGP: usize = 0xFF47; // ignored in CGB mode
    pub const OBP_0: usize = 0xFF48; // ignored in CGB mode
    pub const OBP_1: usize = 0xFF49; // ignored in CGB mode
    pub const WY: usize = 0xFF4A;
    pub const WX: usize = 0xFF4B;
}

/// The structure holding and emulating the GPU state.
///
/// Time durations are expressed in CPU clock cycles with a CPU clock speed of
/// 4194304 Hz.
pub struct Gpu {
    /// If true, a Game Boy Color GPU will be emulated.
    cgb_mode: bool,
    /// CGB-specific data, needed in CGB mode.
    cgb_data: Option<cgb::GpuData>,
    /// The current mode.
    mode: GpuMode,
    /// The number of cycles spent in the current mode.
    mode_clock: CycleType,
    /// The index of the current scanline.
    /// Can take any value between 0 and 153, with values between 144 and 153
    /// indicating a V-Blank period.
    /// Writing to the LY register resets it to 0.
    ly: usize,
    /// Horizontal position of the top-left corner of the on-screen background.
    scroll_x: u8,
    /// Vertical position of the top-left corner of the on-screen background.
    scroll_y: u8,
    // Horizontal position of the top-left of the Window area.
    window_x: u8,
    // Vertical position of the top-left of the Window area.
    window_y: u8,
    /// The frame buffer containing the display's pixels.
    frame_buffer: ScreenData,
    /// The background palette, assigning gray shades to the color numbers
    /// of the background and window tiles.
    /// Not used in CGB mode (yet 'Option' is not used for convenience).
    bg_palette: PaletteClassic,
    /// The two object palettes (Classic mode only), assigning gray shades to
    /// the color numbers of the sprites. Color 0 is not used (transparent).
    /// Not used in CGB mode.
    ob_palettes: [PaletteClassic; 2],
    /// The tileset in VRAM.
    tileset: [Tile; 384],
    /// The two tilemaps in VRAM.
    tilemaps: [[u8; TILEMAP_SIZE]; 2],
    /// Should the screen be redrawn by the frontend ?
    /// Must be externally set to false after that.
    pub dirty: bool,
}

impl Gpu {
    /// Create and return a new 'Gpu' instance.
    pub fn new(cgb_mode: bool) -> Gpu {
        Gpu {
            cgb_mode,
            cgb_data: if cgb_mode {
                Some(cgb::GpuData::new())
            } else {
                None
            },
            mode: H_Blank,
            mode_clock: 0,
            ly: 0,
            scroll_x: 0,
            scroll_y: 0,
            window_x: 0,
            window_y: 0,
            frame_buffer: [RGB::new(255, 255, 255); SCREEN_W * SCREEN_H],
            bg_palette: PaletteClassic::new(),
            ob_palettes: [PaletteClassic::new(); 2],
            tileset: [Tile::new([0x00; 16]); 384],
            tilemaps: [[0x00; TILEMAP_SIZE]; 2],
            dirty: false,
        }
    }

    /// Advance the GPU simulation.
    pub fn step(&mut self, ticks: CycleType, irq_handler: &mut IrqHandler) {
        self.mode_clock += ticks;

        match self.mode {
            // scanline, accessing OAM
            OAM_Read => {
                if self.mode_clock >= 80 {
                    self.switch_mode(VRAM_Read)
                }
            }
            // scanline, accessing VRAM
            VRAM_Read => {
                if self.mode_clock >= 172 {
                    // end of scanline
                    self.switch_mode(H_Blank);
                    self.render_scanline();
                    // TODO : throw LCD_Stat interrupt here ?
                }
            }
            // horizontal blank
            H_Blank => {
                if self.mode_clock >= 204 {
                    self.ly += 1;
                    if self.ly == SCREEN_H {
                        self.switch_mode(V_Blank);
                        self.dirty = true; // the framebuffer can be rendered
                        irq_handler.request_interrupt(Interrupt::V_Blank);
                    } else {
                        self.switch_mode(OAM_Read);
                    }
                }
            }
            // vertical blank (10 lines)
            V_Blank => {
                if self.mode_clock >= 456 {
                    self.mode_clock = 0;
                    self.ly += 1;
                    if self.ly == SCREEN_H + 10 {
                        self.switch_mode(OAM_Read);
                        self.ly = 0;
                    }
                }
            }
        }
    }

    /// Switch the current GPU mode.
    fn switch_mode(&mut self, new_mode: GpuMode) {
        self.mode_clock = 0;
        self.mode = new_mode;
    }

    /// Write the current scanline in the framebuffer.
    fn render_scanline(&mut self) {}
}

impl Memory for Gpu {
    fn read_byte(&mut self, address: u16) -> u8 {
        use self::regs::*;
        use self::cgb::regs as r;

        let a = address as usize;

        if self.cgb_mode {
            let data = self.cgb_data.as_ref().unwrap();
            match a {
                r::VRAM_BANK => return data.vram_bank_selector,
                r::BGP_INDEX => return data.bg_palette_index.raw_value(),
                r::BGP_DATA => return data.get_bg_color(),
                r::OBP_INDEX => return data.ob_palette_index.raw_value(),
                r::OBP_DATA => return data.get_ob_color(),
                _ => {}
            }
        }
        match a {
            0x8000...0x9FFF => {
                // Video RAM
                let bank_address = a & 0x1FFF;
                if self.cgb_mode {
                    let data = self.cgb_data.as_ref().unwrap();
                    if data.vram_bank_selector & 0x01 == 0x01 {
                        // return data.vram_bank[bank_address];
                    }
                }
                // return self.vram_bank[bank_address];
                0
            }
            SCY => self.scroll_y,
            SCX => self.scroll_x,
            LY => self.ly as u8,
            BGP => self.bg_palette.raw(),
            OBP_0 => self.ob_palettes[0].raw(),
            OBP_1 => self.ob_palettes[1].raw(),
            WY => self.window_y,
            WX => self.window_x,
            _ => 0,
        }
    }
    fn write_byte(&mut self, address: u16, byte: u8) {
        use self::regs::*;
        use self::cgb::regs as r;

        let a = address as usize;

        if self.cgb_mode {
            let data = self.cgb_data.as_mut().unwrap();
            let mut done = true;
            match a {
                r::VRAM_BANK => data.vram_bank_selector = byte,
                r::BGP_INDEX => data.bg_palette_index.update_with(byte),
                r::BGP_DATA => data.set_bg_color(byte),
                r::OBP_INDEX => data.ob_palette_index.update_with(byte),
                r::OBP_DATA => data.set_ob_color(byte),
                _ => {
                    done = false;
                }
            }
            if done {
                return;
            }
        }
        match a {
            0x8000...0x9FFF => {
                // Video RAM
                let bank_address = a & 0x1FFF;
                if self.cgb_mode {
                    let data = self.cgb_data.as_mut().unwrap();
                    if data.vram_bank_selector & 0x01 == 0x01 {
                        // data.vram_bank[bank_address] = byte;
                    }
                }
                // self.vram_bank[bank_address] = byte;
            }
            SCY => self.scroll_y = byte,
            SCX => self.scroll_x = byte,
            LY => self.ly = 0,
            BGP => self.bg_palette.set(byte),
            OBP_0 => self.ob_palettes[0].set(byte),
            OBP_1 => self.ob_palettes[1].set(byte),
            WY => self.window_y = byte,
            WX => self.window_x = byte,
            _ => (),
        }
    }
}

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

    #[test]
    fn test_tile_update() {
        // Source for the Tile example: http://fms.komkon.org/GameBoy/Tech/Software.html
        // .33333..                          .33333.. -> 0b0111_1100 -> 0x7C
        // 22...22.                                      0b0111_1100 -> 0x7C
        // 11...11.                          22...22. -> 0b0000_0000 -> 0x00
        // 2222222.                                      0b1100_0110 -> 0xC6
        // 33...33.                          11...11. -> 0b1100_0110 -> 0xC6
        // 22...22.                                      0b0000_0000 -> 0x00
        // 11...11.                          2222222. -> 0b0000_0000 -> 0x00
        // ........                                      0b1111_1110 -> 0xFE
        // 33...33. -> 0b1100_0110 -> 0xC6
        // 0b1100_0110 -> 0xC6
        // 22...22. -> 0b0000_0000 -> 0x00
        // 0b1100_0110 -> 0xC6
        // 11...11. -> 0b1100_0110 -> 0xC6
        // 0b0000_0000 -> 0x00
        // ........ -> 0b0000_0000 -> 0x00
        // 0b0000_0000 -> 0x00
        //
        let tile = Tile::new([
            0x7C, 0x7C, 0x00, 0xC6, 0xC6, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0x00,
            0x00, 0x00,
        ]);
        let data = tile.data();
        let data_test = [
            [0, 3, 3, 3, 3, 3, 0, 0],
            [2, 2, 0, 0, 0, 2, 2, 0],
            [1, 1, 0, 0, 0, 1, 1, 0],
            [2, 2, 2, 2, 2, 2, 2, 0],
            [3, 3, 0, 0, 0, 3, 3, 0],
            [2, 2, 0, 0, 0, 2, 2, 0],
            [1, 1, 0, 0, 0, 1, 1, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
        ];
        for (y, line) in data.iter().enumerate() {
            for (x, color_value) in line.iter().enumerate() {
                assert_eq!(*color_value, data_test[y][x]);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! The executor runs all given futures to completion. Futures register wakers associated with file
//! descriptors. The wakers will be called when the FD becomes readable or writable depending on
//! the situation.
//!
//! `FdExecutor` is meant to be used with the `futures-rs` crate that provides combinators and
//! utility functions to combine futures.
//!
//! # Example of starting the framework and running a future:
//!
//! ```
//! # use std::rc::Rc;
//! # use std::cell::RefCell;
//! use cros_async::Executor;
//! async fn my_async(mut x: Rc<RefCell<u64>>) {
//!     x.replace(4);
//! }
//!
//! let mut ex = cros_async::empty_executor().expect("Failed creating executor");
//! let x = Rc::new(RefCell::new(0));
//! cros_async::fd_executor::add_future(Box::pin(my_async(x.clone())));
//! ex.run();
//! assert_eq!(*x.borrow(), 4);
//! ```

use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::fmt::{self, Display};
use std::fs::File;
use std::future::Future;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::RawFd;
use std::pin::Pin;
use std::task::Waker;

use sys_util::{PollContext, WatchingEvents};

use crate::executor::{ExecutableFuture, Executor, FutureList};

#[derive(Debug, PartialEq)]
pub enum Error {
    /// Attempts to create two Executors on the same thread fail.
    AttemptedDuplicateExecutor,
    /// Failed to copy the FD for the polling context.
    DuplicatingFd(sys_util::Error),
    /// Failed accessing the thread local storage for wakers.
    InvalidContext,
    /// Creating a context to wait on FDs failed.
    CreatingContext(sys_util::Error),
    /// PollContext failure.
    PollContextError(sys_util::Error),
    /// Failed to submit the waker to the polling context.
    SubmittingWaker(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            AttemptedDuplicateExecutor => write!(f, "Cannot have two executors on one thread."),
            DuplicatingFd(e) => write!(f, "Failed to copy the FD for the polling context: {}", e),
            InvalidContext => write!(
                f,
                "Invalid context, was the Fd executor created successfully?"
            ),
            CreatingContext(e) => write!(f, "An error creating the fd waiting context: {}.", e),
            PollContextError(e) => write!(f, "PollContext failure: {}", e),
            SubmittingWaker(e) => write!(f, "An error adding to the Aio context: {}.", e),
        }
    }
}

// Temporary vectors of new additions to the executor.

// Tracks active wakers and the futures they are associated with.
thread_local!(static STATE: RefCell<Option<FdWakerState>> = RefCell::new(None));

/// A token returned from `add_waker` that can be used to cancel the waker before it completes.
pub struct WakerToken(u64);

fn add_waker(fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.add_waker(fd, waker, events)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Tells the waking system to wake `waker` when `fd` becomes readable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_read_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_read())
}

/// Tells the waking system to wake `waker` when `fd` becomes writable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_write_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_write())
}

/// Cancels the waker that returned the given token if the waker hasn't yet fired.
pub fn cancel_waker(token: WakerToken) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.cancel_waker(token)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Adds a new top level future to the Executor.
/// These futures must return `()`, indicating they are intended to create side-effects only.
pub fn add_future(future: Pin<Box<dyn Future<Output = ()>>>) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.new_futures.push_back(ExecutableFuture::new(future));
            Ok(())
        } else {
            Err(Error::InvalidContext)
        }
    })
}

// Tracks active wakers and associates wakers with the futures that registered them.
struct FdWakerState {
    poll_ctx: PollContext<u64>,
    token_map: BTreeMap<u64, (File, Waker)>,
    next_token: u64, // Next token for adding to the context.
    new_futures: VecDeque<ExecutableFuture<()>>,
}

impl FdWakerState {
    fn new() -> Result<Self> {
        Ok(FdWakerState {
            poll_ctx: PollContext::new().map_err(Error::CreatingContext)?,
            token_map: BTreeMap::new(),
            next_token: 0,
            new_futures: VecDeque::new(),
        })
    }

    // Adds an fd that, when signaled, will trigger the given waker.
    fn add_waker(&mut self, fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
        let duped_fd = unsafe {
            // Safe because duplicating an FD doesn't affect memory safety, and the dup'd FD
            // will only be added to the poll loop.
            File::from_raw_fd(dup_fd(fd)?)
        };
        self.poll_ctx
            .add_fd_with_events(&duped_fd, events, self.next_token)
            .map_err(Error::SubmittingWaker)?;
        let next_token = self.next_token;
        self.token_map.insert(next_token, (duped_fd, waker));
        self.next_token += 1;
        Ok(WakerToken(next_token))
    }

    // Waits until one of the FDs is readable and wakes the associated waker.
    fn wait_wake_event(&mut self) -> Result<()> {
        let events = self.poll_ctx.wait().map_err(Error::PollContextError)?;
        for e in events.iter() {
            if let Some((fd, waker)) = self.token_map.remove(&e.token()) {
                self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
                waker.wake_by_ref();
            }
        }
        Ok(())
    }

    // Remove the waker for the given token if it hasn't fired yet.
    fn cancel_waker(&mut self, token: WakerToken) -> Result<()> {
        if let Some((fd, waker)) = self.token_map.remove(&token.0) {
            self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
            waker.wake_by_ref();
        }
        Ok(())
    }
}

/// Runs futures to completion on a single thread. Futures are allowed to block on file descriptors
/// only. Futures can only block on FDs becoming readable or writable. `FdExecutor` is meant to be
/// used where a poll or select loop would be used otherwise.
pub(crate) struct FdExecutor<T: FutureList> {
    futures: T,
}

impl<T: FutureList> Executor for FdExecutor<T> {
    type Output = Result<T::Output>;

    fn run(&mut self) -> Self::Output {
        self.append_futures();

        loop {
            if let Some(output) = self.futures.poll_results() {
                return Ok(output);
            }

            self.append_futures();

            // If no futures are ready, sleep until a waker is signaled.
            if !self.futures.any_ready() {
                STATE.with(|state| {
                    let mut state = state.borrow_mut();
                    if let Some(state) = state.as_mut() {
                        state.wait_wake_event()?;
                    } else {
                        unreachable!("Can't get here without a context being created");
                    }
                    Ok(())
                })?;
            }
        }
    }
}

impl<T: FutureList> FdExecutor<T> {
    /// Create a new executor.
    pub fn new(futures: T) -> Result<FdExecutor<T>> {
        STATE.with(|state| {
            if state.borrow().is_some() {
                return Err(Error::AttemptedDuplicateExecutor);
            }
            state.replace(Some(FdWakerState::new()?));
            Ok(())
        })?;
        Ok(FdExecutor { futures })
    }

    // Add any new futures and wakers to the lists.
    fn append_futures(&mut self) {
        STATE.with(|state| {
            let mut state = state.borrow_mut();
            if let Some(state) = state.as_mut() {
                self.futures.futures_mut().append(&mut state.new_futures);
            } else {
                unreachable!("Can't get here without a context being created");
            }
        });
    }
}

impl<T: FutureList> Drop for FdExecutor<T> {
    fn drop(&mut self) {
        STATE.with(|state| {
            state.replace(None);
        });
    }
}

// Used to dup the FDs passed to the executor so there is a guarantee they aren't closed while
// waiting in TLS to be added to the main polling context.
unsafe fn dup_fd(fd: RawFd) -> Result<RawFd> {
    let ret = libc::dup(fd);
    if ret < 0 {
        Err(Error::DuplicatingFd(sys_util::Error::last()))
    } else {
        Ok(ret)
    }
}

#[cfg(test)]
mod test {
    use std::future::Future;
    use std::os::unix::io::AsRawFd;
    use std::task::{Context, Poll};

    use futures::future::Either;
    use futures::pin_mut;

    use super::*;

    struct TestFut {
        f: File,
        token: Option<WakerToken>,
    }

    impl TestFut {
        fn new(f: File) -> TestFut {
            TestFut { f, token: None }
        }
    }

    impl Future for TestFut {
        type Output = u64;
        fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
            if self.token.is_none() {
                self.token = Some(add_read_waker(self.f.as_raw_fd(), cx.waker().clone()).unwrap());
            }
            Poll::Pending
        }
    }

    impl Drop for TestFut {
        fn drop(&mut self) {
            if let Some(token) = self.token.take() {
                cancel_waker(token).unwrap();
            }
        }
    }

    #[test]
    fn cancel() {
        async fn do_test() {
            let (r, _w) = sys_util::pipe(true).unwrap();
            let done = async { 5usize };
            let pending = TestFut::new(r);
            pin_mut!(done);
            pin_mut!(pending);
            match futures::future::select(pending, done).await {
                Either::Right((5, _pending)) => (),
                _ => panic!("unexpected select result"),
            }
        }

        let fut = do_test();

        let mut ex = FdExecutor::new(crate::UnitFutures::new()).expect("Failed creating executor");
        add_future(Box::pin(fut)).unwrap();
        ex.run().unwrap();
        STATE.with(|state| {
            let state = state.borrow_mut();
            assert!(state.as_ref().unwrap().token_map.is_empty());
        });
    }
}
<commit_msg>cros_async: Don't wake wakers on removal<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! The executor runs all given futures to completion. Futures register wakers associated with file
//! descriptors. The wakers will be called when the FD becomes readable or writable depending on
//! the situation.
//!
//! `FdExecutor` is meant to be used with the `futures-rs` crate that provides combinators and
//! utility functions to combine futures.
//!
//! # Example of starting the framework and running a future:
//!
//! ```
//! # use std::rc::Rc;
//! # use std::cell::RefCell;
//! use cros_async::Executor;
//! async fn my_async(mut x: Rc<RefCell<u64>>) {
//!     x.replace(4);
//! }
//!
//! let mut ex = cros_async::empty_executor().expect("Failed creating executor");
//! let x = Rc::new(RefCell::new(0));
//! cros_async::fd_executor::add_future(Box::pin(my_async(x.clone())));
//! ex.run();
//! assert_eq!(*x.borrow(), 4);
//! ```

use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::fmt::{self, Display};
use std::fs::File;
use std::future::Future;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::RawFd;
use std::pin::Pin;
use std::task::Waker;

use sys_util::{PollContext, WatchingEvents};

use crate::executor::{ExecutableFuture, Executor, FutureList};

#[derive(Debug, PartialEq)]
pub enum Error {
    /// Attempts to create two Executors on the same thread fail.
    AttemptedDuplicateExecutor,
    /// Failed to copy the FD for the polling context.
    DuplicatingFd(sys_util::Error),
    /// Failed accessing the thread local storage for wakers.
    InvalidContext,
    /// Creating a context to wait on FDs failed.
    CreatingContext(sys_util::Error),
    /// PollContext failure.
    PollContextError(sys_util::Error),
    /// Failed to submit the waker to the polling context.
    SubmittingWaker(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            AttemptedDuplicateExecutor => write!(f, "Cannot have two executors on one thread."),
            DuplicatingFd(e) => write!(f, "Failed to copy the FD for the polling context: {}", e),
            InvalidContext => write!(
                f,
                "Invalid context, was the Fd executor created successfully?"
            ),
            CreatingContext(e) => write!(f, "An error creating the fd waiting context: {}.", e),
            PollContextError(e) => write!(f, "PollContext failure: {}", e),
            SubmittingWaker(e) => write!(f, "An error adding to the Aio context: {}.", e),
        }
    }
}

// Temporary vectors of new additions to the executor.

// Tracks active wakers and the futures they are associated with.
thread_local!(static STATE: RefCell<Option<FdWakerState>> = RefCell::new(None));

/// A token returned from `add_waker` that can be used to cancel the waker before it completes.
pub struct WakerToken(u64);

fn add_waker(fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.add_waker(fd, waker, events)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Tells the waking system to wake `waker` when `fd` becomes readable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_read_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_read())
}

/// Tells the waking system to wake `waker` when `fd` becomes writable.
/// The 'fd' must be fully owned by the future adding the waker, and must not be closed until the
/// next time the future is polled. If the fd is closed, there is a race where another FD can be
/// opened on top of it causing the next poll to access the new target file.
/// Returns a `WakerToken` that can be used to cancel the waker before it completes.
pub fn add_write_waker(fd: RawFd, waker: Waker) -> Result<WakerToken> {
    add_waker(fd, waker, WatchingEvents::empty().set_write())
}

/// Cancels the waker that returned the given token if the waker hasn't yet fired.
pub fn cancel_waker(token: WakerToken) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.cancel_waker(token)
        } else {
            Err(Error::InvalidContext)
        }
    })
}

/// Adds a new top level future to the Executor.
/// These futures must return `()`, indicating they are intended to create side-effects only.
pub fn add_future(future: Pin<Box<dyn Future<Output = ()>>>) -> Result<()> {
    STATE.with(|state| {
        let mut state = state.borrow_mut();
        if let Some(state) = state.as_mut() {
            state.new_futures.push_back(ExecutableFuture::new(future));
            Ok(())
        } else {
            Err(Error::InvalidContext)
        }
    })
}

// Tracks active wakers and associates wakers with the futures that registered them.
struct FdWakerState {
    poll_ctx: PollContext<u64>,
    token_map: BTreeMap<u64, (File, Waker)>,
    next_token: u64, // Next token for adding to the context.
    new_futures: VecDeque<ExecutableFuture<()>>,
}

impl FdWakerState {
    fn new() -> Result<Self> {
        Ok(FdWakerState {
            poll_ctx: PollContext::new().map_err(Error::CreatingContext)?,
            token_map: BTreeMap::new(),
            next_token: 0,
            new_futures: VecDeque::new(),
        })
    }

    // Adds an fd that, when signaled, will trigger the given waker.
    fn add_waker(&mut self, fd: RawFd, waker: Waker, events: WatchingEvents) -> Result<WakerToken> {
        let duped_fd = unsafe {
            // Safe because duplicating an FD doesn't affect memory safety, and the dup'd FD
            // will only be added to the poll loop.
            File::from_raw_fd(dup_fd(fd)?)
        };
        self.poll_ctx
            .add_fd_with_events(&duped_fd, events, self.next_token)
            .map_err(Error::SubmittingWaker)?;
        let next_token = self.next_token;
        self.token_map.insert(next_token, (duped_fd, waker));
        self.next_token += 1;
        Ok(WakerToken(next_token))
    }

    // Waits until one of the FDs is readable and wakes the associated waker.
    fn wait_wake_event(&mut self) -> Result<()> {
        let events = self.poll_ctx.wait().map_err(Error::PollContextError)?;
        for e in events.iter() {
            if let Some((fd, waker)) = self.token_map.remove(&e.token()) {
                self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
                waker.wake_by_ref();
            }
        }
        Ok(())
    }

    // Remove the waker for the given token if it hasn't fired yet.
    fn cancel_waker(&mut self, token: WakerToken) -> Result<()> {
        if let Some((fd, _waker)) = self.token_map.remove(&token.0) {
            self.poll_ctx.delete(&fd).map_err(Error::PollContextError)?;
        }
        Ok(())
    }
}

/// Runs futures to completion on a single thread. Futures are allowed to block on file descriptors
/// only. Futures can only block on FDs becoming readable or writable. `FdExecutor` is meant to be
/// used where a poll or select loop would be used otherwise.
pub(crate) struct FdExecutor<T: FutureList> {
    futures: T,
}

impl<T: FutureList> Executor for FdExecutor<T> {
    type Output = Result<T::Output>;

    fn run(&mut self) -> Self::Output {
        self.append_futures();

        loop {
            if let Some(output) = self.futures.poll_results() {
                return Ok(output);
            }

            self.append_futures();

            // If no futures are ready, sleep until a waker is signaled.
            if !self.futures.any_ready() {
                STATE.with(|state| {
                    let mut state = state.borrow_mut();
                    if let Some(state) = state.as_mut() {
                        state.wait_wake_event()?;
                    } else {
                        unreachable!("Can't get here without a context being created");
                    }
                    Ok(())
                })?;
            }
        }
    }
}

impl<T: FutureList> FdExecutor<T> {
    /// Create a new executor.
    pub fn new(futures: T) -> Result<FdExecutor<T>> {
        STATE.with(|state| {
            if state.borrow().is_some() {
                return Err(Error::AttemptedDuplicateExecutor);
            }
            state.replace(Some(FdWakerState::new()?));
            Ok(())
        })?;
        Ok(FdExecutor { futures })
    }

    // Add any new futures and wakers to the lists.
    fn append_futures(&mut self) {
        STATE.with(|state| {
            let mut state = state.borrow_mut();
            if let Some(state) = state.as_mut() {
                self.futures.futures_mut().append(&mut state.new_futures);
            } else {
                unreachable!("Can't get here without a context being created");
            }
        });
    }
}

impl<T: FutureList> Drop for FdExecutor<T> {
    fn drop(&mut self) {
        STATE.with(|state| {
            state.replace(None);
        });
    }
}

// Used to dup the FDs passed to the executor so there is a guarantee they aren't closed while
// waiting in TLS to be added to the main polling context.
unsafe fn dup_fd(fd: RawFd) -> Result<RawFd> {
    let ret = libc::dup(fd);
    if ret < 0 {
        Err(Error::DuplicatingFd(sys_util::Error::last()))
    } else {
        Ok(ret)
    }
}

#[cfg(test)]
mod test {
    use std::future::Future;
    use std::os::unix::io::AsRawFd;
    use std::task::{Context, Poll};

    use futures::future::Either;
    use futures::pin_mut;

    use super::*;

    struct TestFut {
        f: File,
        token: Option<WakerToken>,
    }

    impl TestFut {
        fn new(f: File) -> TestFut {
            TestFut { f, token: None }
        }
    }

    impl Future for TestFut {
        type Output = u64;
        fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
            if self.token.is_none() {
                self.token = Some(add_read_waker(self.f.as_raw_fd(), cx.waker().clone()).unwrap());
            }
            Poll::Pending
        }
    }

    impl Drop for TestFut {
        fn drop(&mut self) {
            if let Some(token) = self.token.take() {
                cancel_waker(token).unwrap();
            }
        }
    }

    #[test]
    fn cancel() {
        async fn do_test() {
            let (r, _w) = sys_util::pipe(true).unwrap();
            let done = async { 5usize };
            let pending = TestFut::new(r);
            pin_mut!(done);
            pin_mut!(pending);
            match futures::future::select(pending, done).await {
                Either::Right((5, _pending)) => (),
                _ => panic!("unexpected select result"),
            }
        }

        let fut = do_test();

        let mut ex = FdExecutor::new(crate::UnitFutures::new()).expect("Failed creating executor");
        add_future(Box::pin(fut)).unwrap();
        ex.run().unwrap();
        STATE.with(|state| {
            let state = state.borrow_mut();
            assert!(state.as_ref().unwrap().token_map.is_empty());
        });
    }
}
<|endoftext|>


<commit_before>use core::ops;

macro_rules! hty {
    ($ty:ty) => {
        <$ty as LargeInt>::HighHalf
    }
}

macro_rules! os_ty {
    ($ty:ty) => {
        <$ty as Int>::OtherSign
    }
}

pub mod addsub;
pub mod mul;
pub mod sdiv;
pub mod shift;
pub mod udiv;

/// Trait for some basic operations on integers
pub trait Int:
    Copy +
    PartialEq +
    PartialOrd +
    ops::AddAssign +
    ops::BitAndAssign +
    ops::BitOrAssign +
    ops::ShlAssign<i32> +
    ops::ShrAssign<u32> +
    ops::Add<Output = Self> +
    ops::Sub<Output = Self> +
    ops::Div<Output = Self> +
    ops::Shl<u32, Output = Self> +
    ops::Shr<u32, Output = Self> +
    ops::BitOr<Output = Self> +
    ops::BitXor<Output = Self> +
    ops::BitAnd<Output = Self> +
    ops::Not<Output = Self> +
{
    /// Type with the same width but other signedness
    type OtherSign: Int;
    /// Unsigned version of Self
    type UnsignedInt: Int;

    /// The bitwidth of the int type
    const BITS: u32;

    const ZERO: Self;
    const ONE: Self;

    /// Extracts the sign from self and returns a tuple.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// let i = -25_i32;
    /// let (sign, u) = i.extract_sign();
    /// assert_eq!(sign, true);
    /// assert_eq!(u, 25_u32);
    /// ```
    fn extract_sign(self) -> (bool, Self::UnsignedInt);

    fn unsigned(self) -> Self::UnsignedInt;
    fn from_unsigned(unsigned: Self::UnsignedInt) -> Self;

    fn from_bool(b: bool) -> Self;

    // copied from primitive integers, but put in a trait
    fn max_value() -> Self;
    fn min_value() -> Self;
    fn wrapping_add(self, other: Self) -> Self;
    fn wrapping_mul(self, other: Self) -> Self;
    fn wrapping_sub(self, other: Self) -> Self;
    fn wrapping_shl(self, other: u32) -> Self;
    fn overflowing_add(self, other: Self) -> (Self, bool);
    fn aborting_div(self, other: Self) -> Self;
    fn aborting_rem(self, other: Self) -> Self;
    fn leading_zeros(self) -> u32;
}

fn unwrap<T>(t: Option<T>) -> T {
    match t {
        Some(t) => t,
        None => ::abort(),
    }
}

macro_rules! int_impl_common {
    ($ty:ty, $bits:expr) => {
            const BITS: u32 = $bits;

            const ZERO: Self = 0;
            const ONE: Self = 1;

            fn from_bool(b: bool) -> Self {
                b as $ty
            }

            fn max_value() -> Self {
                <Self>::max_value()
            }

            fn min_value() -> Self {
                <Self>::min_value()
            }

            fn wrapping_add(self, other: Self) -> Self {
                <Self>::wrapping_add(self, other)
            }

            fn wrapping_mul(self, other: Self) -> Self {
                <Self>::wrapping_mul(self, other)
            }

            fn wrapping_sub(self, other: Self) -> Self {
                <Self>::wrapping_sub(self, other)
            }

            fn wrapping_shl(self, other: u32) -> Self {
                <Self>::wrapping_shl(self, other)
            }

            fn overflowing_add(self, other: Self) -> (Self, bool) {
                <Self>::overflowing_add(self, other)
            }

            fn aborting_div(self, other: Self) -> Self {
                unwrap(<Self>::checked_div(self, other))
            }

            fn aborting_rem(self, other: Self) -> Self {
                unwrap(<Self>::checked_rem(self, other))
            }

            fn leading_zeros(self) -> u32 {
                <Self>::leading_zeros(self)
            }
    }
}

macro_rules! int_impl {
    ($ity:ty, $uty:ty, $bits:expr) => {
        impl Int for $uty {
            type OtherSign = $ity;
            type UnsignedInt = $uty;

            fn extract_sign(self) -> (bool, $uty) {
                (false, self)
            }

            fn unsigned(self) -> $uty {
                self
            }

            fn from_unsigned(me: $uty) -> Self {
                me
            }

            int_impl_common!($uty, $bits);
        }

        impl Int for $ity {
            type OtherSign = $uty;
            type UnsignedInt = $uty;

            fn extract_sign(self) -> (bool, $uty) {
                if self < 0 {
                    (true, (!(self as $uty)).wrapping_add(1))
                } else {
                    (false, self as $uty)
                }
            }

            fn unsigned(self) -> $uty {
                self as $uty
            }

            fn from_unsigned(me: $uty) -> Self {
                me as $ity
            }

            int_impl_common!($ity, $bits);
        }
    }
}

int_impl!(i32, u32, 32);
int_impl!(i64, u64, 64);
int_impl!(i128, u128, 128);

/// Trait to convert an integer to/from smaller parts
pub trait LargeInt: Int {
    type LowHalf: Int;
    type HighHalf: Int;

    fn low(self) -> Self::LowHalf;
    fn low_as_high(low: Self::LowHalf) -> Self::HighHalf;
    fn high(self) -> Self::HighHalf;
    fn high_as_low(low: Self::HighHalf) -> Self::LowHalf;
    fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self;
}

macro_rules! large_int {
    ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => {
        impl LargeInt for $ty {
            type LowHalf = $tylow;
            type HighHalf = $tyhigh;

            fn low(self) -> $tylow {
                self as $tylow
            }
            fn low_as_high(low: $tylow) -> $tyhigh {
                low as $tyhigh
            }
            fn high(self) -> $tyhigh {
                (self >> $halfbits) as $tyhigh
            }
            fn high_as_low(high: $tyhigh) -> $tylow {
                high as $tylow
            }
            fn from_parts(low: $tylow, high: $tyhigh) -> $ty {
                low as $ty | ((high as $ty) << $halfbits)
            }
        }
    }
}

large_int!(u64, u32, u32, 32);
large_int!(i64, u32, i32, 32);
large_int!(u128, u64, u64, 64);
large_int!(i128, u64, i64, 64);

/// Trait to express (possibly lossy) casting of integers
pub trait CastInto<T: Copy>: Copy {
    fn cast(self) -> T;
}

macro_rules! cast_into {
    ($ty:ty) => {
        cast_into!($ty; usize, isize, u32, i32, u64, i64, u128, i128);
    };
    ($ty:ty; $($into:ty),*) => {$(
        impl CastInto<$into> for $ty {
            fn cast(self) -> $into {
                self as $into
            }
        }
    )*};
}

cast_into!(u32);
cast_into!(i32);
cast_into!(u64);
cast_into!(i64);
cast_into!(u128);
cast_into!(i128);

pub trait WideInt: Int {
    type Output: Int;

    fn wide_mul(self, other: Self) -> (Self, Self);
    fn wide_shift_left(&mut self, low: &mut Self, count: i32);
    fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32);
}

macro_rules! impl_wide_int {
    ($ty:ty, $tywide:ty, $bits:expr) => {
        impl WideInt for $ty {
            type Output = $ty;

            fn wide_mul(self, other: Self) -> (Self, Self) {
                let product = (self as $tywide).wrapping_mul(other as $tywide);
                ((product >> ($bits as $ty)) as $ty, product as $ty)
            }

            fn wide_shift_left(&mut self, low: &mut Self, count: i32) {
                *self = (*self << count) | (*low >> ($bits - count));
                *low = *low << count;
            }

            fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) {
                if count < $bits {
                    let sticky = *low << ($bits - count);
                    *low = *self << ($bits - count) | *low >> count | sticky;
                    *self = *self >> count;
                } else if count < 2*$bits {
                    let sticky = *self << (2*$bits - count) | *low;
                    *low = *self >> (count - $bits ) | sticky;
                    *self = 0;
                } else {
                    let sticky = *self | *low;
                    *self = sticky;
                    *self = 0;
                }
            }
        }
    }
}

impl_wide_int!(u32, u64, 32);
impl_wide_int!(u64, u128, 64);

#[no_mangle]
#[cfg(any(
    target_pointer_width = "16",
    target_pointer_width = "32",
    target_pointer_width = "64"
))]
pub extern "C" fn __clzsi2(mut x: usize) -> usize {
    // TODO: const this? Would require const-if
    let mut y: usize;
    let mut n: usize = {
        #[cfg(target_pointer_width = "64")]
        {
            64
        }
        #[cfg(target_pointer_width = "32")]
        {
            32
        }
        #[cfg(target_pointer_width = "16")]
        {
            16
        }
    };
    #[cfg(target_pointer_width = "64")]
    {
        y = x >> 32;
        if y != 0 {
            n -= 32;
            x = y;
        }
    }
    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
    {
        y = x >> 16;
        if y != 0 {
            n -= 16;
            x = y;
        }
    }
    y = x >> 8;
    if y != 0 {
        n -= 8;
        x = y;
    }
    y = x >> 4;
    if y != 0 {
        n -= 4;
        x = y;
    }
    y = x >> 2;
    if y != 0 {
        n -= 2;
        x = y;
    }
    y = x >> 1;
    if y != 0 {
        n - 2
    } else {
        n - x
    }
}
<commit_msg>Attempt to use `intrinsics!`<commit_after>use core::ops;

macro_rules! hty {
    ($ty:ty) => {
        <$ty as LargeInt>::HighHalf
    }
}

macro_rules! os_ty {
    ($ty:ty) => {
        <$ty as Int>::OtherSign
    }
}

pub mod addsub;
pub mod mul;
pub mod sdiv;
pub mod shift;
pub mod udiv;

/// Trait for some basic operations on integers
pub trait Int:
    Copy +
    PartialEq +
    PartialOrd +
    ops::AddAssign +
    ops::BitAndAssign +
    ops::BitOrAssign +
    ops::ShlAssign<i32> +
    ops::ShrAssign<u32> +
    ops::Add<Output = Self> +
    ops::Sub<Output = Self> +
    ops::Div<Output = Self> +
    ops::Shl<u32, Output = Self> +
    ops::Shr<u32, Output = Self> +
    ops::BitOr<Output = Self> +
    ops::BitXor<Output = Self> +
    ops::BitAnd<Output = Self> +
    ops::Not<Output = Self> +
{
    /// Type with the same width but other signedness
    type OtherSign: Int;
    /// Unsigned version of Self
    type UnsignedInt: Int;

    /// The bitwidth of the int type
    const BITS: u32;

    const ZERO: Self;
    const ONE: Self;

    /// Extracts the sign from self and returns a tuple.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// let i = -25_i32;
    /// let (sign, u) = i.extract_sign();
    /// assert_eq!(sign, true);
    /// assert_eq!(u, 25_u32);
    /// ```
    fn extract_sign(self) -> (bool, Self::UnsignedInt);

    fn unsigned(self) -> Self::UnsignedInt;
    fn from_unsigned(unsigned: Self::UnsignedInt) -> Self;

    fn from_bool(b: bool) -> Self;

    // copied from primitive integers, but put in a trait
    fn max_value() -> Self;
    fn min_value() -> Self;
    fn wrapping_add(self, other: Self) -> Self;
    fn wrapping_mul(self, other: Self) -> Self;
    fn wrapping_sub(self, other: Self) -> Self;
    fn wrapping_shl(self, other: u32) -> Self;
    fn overflowing_add(self, other: Self) -> (Self, bool);
    fn aborting_div(self, other: Self) -> Self;
    fn aborting_rem(self, other: Self) -> Self;
    fn leading_zeros(self) -> u32;
}

fn unwrap<T>(t: Option<T>) -> T {
    match t {
        Some(t) => t,
        None => ::abort(),
    }
}

macro_rules! int_impl_common {
    ($ty:ty, $bits:expr) => {
            const BITS: u32 = $bits;

            const ZERO: Self = 0;
            const ONE: Self = 1;

            fn from_bool(b: bool) -> Self {
                b as $ty
            }

            fn max_value() -> Self {
                <Self>::max_value()
            }

            fn min_value() -> Self {
                <Self>::min_value()
            }

            fn wrapping_add(self, other: Self) -> Self {
                <Self>::wrapping_add(self, other)
            }

            fn wrapping_mul(self, other: Self) -> Self {
                <Self>::wrapping_mul(self, other)
            }

            fn wrapping_sub(self, other: Self) -> Self {
                <Self>::wrapping_sub(self, other)
            }

            fn wrapping_shl(self, other: u32) -> Self {
                <Self>::wrapping_shl(self, other)
            }

            fn overflowing_add(self, other: Self) -> (Self, bool) {
                <Self>::overflowing_add(self, other)
            }

            fn aborting_div(self, other: Self) -> Self {
                unwrap(<Self>::checked_div(self, other))
            }

            fn aborting_rem(self, other: Self) -> Self {
                unwrap(<Self>::checked_rem(self, other))
            }

            fn leading_zeros(self) -> u32 {
                <Self>::leading_zeros(self)
            }
    }
}

macro_rules! int_impl {
    ($ity:ty, $uty:ty, $bits:expr) => {
        impl Int for $uty {
            type OtherSign = $ity;
            type UnsignedInt = $uty;

            fn extract_sign(self) -> (bool, $uty) {
                (false, self)
            }

            fn unsigned(self) -> $uty {
                self
            }

            fn from_unsigned(me: $uty) -> Self {
                me
            }

            int_impl_common!($uty, $bits);
        }

        impl Int for $ity {
            type OtherSign = $uty;
            type UnsignedInt = $uty;

            fn extract_sign(self) -> (bool, $uty) {
                if self < 0 {
                    (true, (!(self as $uty)).wrapping_add(1))
                } else {
                    (false, self as $uty)
                }
            }

            fn unsigned(self) -> $uty {
                self as $uty
            }

            fn from_unsigned(me: $uty) -> Self {
                me as $ity
            }

            int_impl_common!($ity, $bits);
        }
    }
}

int_impl!(i32, u32, 32);
int_impl!(i64, u64, 64);
int_impl!(i128, u128, 128);

/// Trait to convert an integer to/from smaller parts
pub trait LargeInt: Int {
    type LowHalf: Int;
    type HighHalf: Int;

    fn low(self) -> Self::LowHalf;
    fn low_as_high(low: Self::LowHalf) -> Self::HighHalf;
    fn high(self) -> Self::HighHalf;
    fn high_as_low(low: Self::HighHalf) -> Self::LowHalf;
    fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self;
}

macro_rules! large_int {
    ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => {
        impl LargeInt for $ty {
            type LowHalf = $tylow;
            type HighHalf = $tyhigh;

            fn low(self) -> $tylow {
                self as $tylow
            }
            fn low_as_high(low: $tylow) -> $tyhigh {
                low as $tyhigh
            }
            fn high(self) -> $tyhigh {
                (self >> $halfbits) as $tyhigh
            }
            fn high_as_low(high: $tyhigh) -> $tylow {
                high as $tylow
            }
            fn from_parts(low: $tylow, high: $tyhigh) -> $ty {
                low as $ty | ((high as $ty) << $halfbits)
            }
        }
    }
}

large_int!(u64, u32, u32, 32);
large_int!(i64, u32, i32, 32);
large_int!(u128, u64, u64, 64);
large_int!(i128, u64, i64, 64);

/// Trait to express (possibly lossy) casting of integers
pub trait CastInto<T: Copy>: Copy {
    fn cast(self) -> T;
}

macro_rules! cast_into {
    ($ty:ty) => {
        cast_into!($ty; usize, isize, u32, i32, u64, i64, u128, i128);
    };
    ($ty:ty; $($into:ty),*) => {$(
        impl CastInto<$into> for $ty {
            fn cast(self) -> $into {
                self as $into
            }
        }
    )*};
}

cast_into!(u32);
cast_into!(i32);
cast_into!(u64);
cast_into!(i64);
cast_into!(u128);
cast_into!(i128);

pub trait WideInt: Int {
    type Output: Int;

    fn wide_mul(self, other: Self) -> (Self, Self);
    fn wide_shift_left(&mut self, low: &mut Self, count: i32);
    fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32);
}

macro_rules! impl_wide_int {
    ($ty:ty, $tywide:ty, $bits:expr) => {
        impl WideInt for $ty {
            type Output = $ty;

            fn wide_mul(self, other: Self) -> (Self, Self) {
                let product = (self as $tywide).wrapping_mul(other as $tywide);
                ((product >> ($bits as $ty)) as $ty, product as $ty)
            }

            fn wide_shift_left(&mut self, low: &mut Self, count: i32) {
                *self = (*self << count) | (*low >> ($bits - count));
                *low = *low << count;
            }

            fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) {
                if count < $bits {
                    let sticky = *low << ($bits - count);
                    *low = *self << ($bits - count) | *low >> count | sticky;
                    *self = *self >> count;
                } else if count < 2*$bits {
                    let sticky = *self << (2*$bits - count) | *low;
                    *low = *self >> (count - $bits ) | sticky;
                    *self = 0;
                } else {
                    let sticky = *self | *low;
                    *self = sticky;
                    *self = 0;
                }
            }
        }
    }
}

impl_wide_int!(u32, u64, 32);
impl_wide_int!(u64, u128, 64);

intrinsics! {
    #[cfg(any(
        target_pointer_width = "16",
        target_pointer_width = "32",
        target_pointer_width = "64"
    ))]
    pub extern "C" fn __clzsi2(x: usize) -> usize {
        // TODO: const this? Would require const-if
        // Note(Lokathor): the `intrinsics!` macro can't process mut inputs
        let mut x = x;
        let mut y: usize;
        let mut n: usize = {
            #[cfg(target_pointer_width = "64")]
            {
                64
            }
            #[cfg(target_pointer_width = "32")]
            {
                32
            }
            #[cfg(target_pointer_width = "16")]
            {
                16
            }
        };
        #[cfg(target_pointer_width = "64")]
        {
            y = x >> 32;
            if y != 0 {
                n -= 32;
                x = y;
            }
        }
        #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
        {
            y = x >> 16;
            if y != 0 {
                n -= 16;
                x = y;
            }
        }
        y = x >> 8;
        if y != 0 {
            n -= 8;
            x = y;
        }
        y = x >> 4;
        if y != 0 {
            n -= 4;
            x = y;
        }
        y = x >> 2;
        if y != 0 {
            n -= 2;
            x = y;
        }
        y = x >> 1;
        if y != 0 {
            n - 2
        } else {
            n - x
        }
    }
}
<|endoftext|>


<commit_before>use std::hash::BuildHasher;
use ahash::{ABuildHasher, AHasher};

#[macro_use]
extern crate no_panic;

#[inline(never)]
#[no_panic]
fn hash_test_final(num: i32, string: &str) -> (u64, u64) {
    use core::hash::Hasher;
    let mut hasher1 = AHasher::new_with_keys(0 ,1);
    let mut hasher2 = AHasher::new_with_keys(0 ,2);
    hasher1.write_i32(num);
    hasher2.write(string.as_bytes());
    (hasher1.finish(), hasher2.finish())
}

#[inline(never)]
fn hash_test_final_wrapper(num: i32, string: &str) {
    hash_test_final(num, string);
}

#[test]
fn test_no_panic() {
    hash_test_final_wrapper(2, "");
}
<commit_msg>Remove unused imports<commit_after>use ahash::{AHasher};

#[macro_use]
extern crate no_panic;

#[inline(never)]
#[no_panic]
fn hash_test_final(num: i32, string: &str) -> (u64, u64) {
    use core::hash::Hasher;
    let mut hasher1 = AHasher::new_with_keys(0 ,1);
    let mut hasher2 = AHasher::new_with_keys(0 ,2);
    hasher1.write_i32(num);
    hasher2.write(string.as_bytes());
    (hasher1.finish(), hasher2.finish())
}

#[inline(never)]
fn hash_test_final_wrapper(num: i32, string: &str) {
    hash_test_final(num, string);
}

#[test]
fn test_no_panic() {
    hash_test_final_wrapper(2, "");
}
<|endoftext|>


<commit_before>/// wrapper for `in` and `out` asm commands.
/// it is `read` and `write` because `in` is a rust keyword.

// FIXME: remake it! Create a `port` struct, which know what should be written and read.

use ::core::marker::PhantomData;

pub struct IOPort<In, Out> {
    num: u16,
    phantom_in: PhantomData<In>,
    phantom_out: PhantomData<Out>,
}

impl<In, Out> IOPort<In, Out> {
    pub const fn new(num: u16) -> Self {
        IOPort { num: num, phantom_in: PhantomData{}, phantom_out: PhantomData{} }
    }
}

pub trait InPort {
    type Type;
    unsafe fn read(&mut self) -> Self::Type;
}

pub trait OutPort {
    type Type;
    unsafe fn write(&mut self, data: Self::Type);
}

impl<Out> InPort for IOPort<u8, Out> {
    type Type = u8;

    unsafe fn read(&mut self) -> u8 {
        let ret: u8;
        asm!("inb %dx, %al" : "={al}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u8> {
    type Type = u8;

    unsafe fn write(&mut self, data: u8) {
        asm!("outb %al, %dx" :  : "{al}"(data), "{dx}"(self.num) :  : "volatile");
    }
}
<commit_msg>new ioports completed<commit_after>/// wrapper for `in` and `out` asm commands.
/// it is `read` and `write` because `in` is a rust keyword.

// FIXME: remake it! Create a `port` struct, which know what should be written and read.

use ::core::marker::PhantomData;

pub struct IOPort<In, Out> {
    num: u16,
    phantom_in: PhantomData<In>,
    phantom_out: PhantomData<Out>,
}

impl<In, Out> IOPort<In, Out> {
    pub const fn new(num: u16) -> Self {
        IOPort { num: num, phantom_in: PhantomData{}, phantom_out: PhantomData{} }
    }
}

pub trait InPort {
    type Type;
    unsafe fn read(&mut self) -> Self::Type;
}

pub trait OutPort {
    type Type;
    unsafe fn write(&mut self, data: Self::Type);
}

impl<Out> InPort for IOPort<u8, Out> {
    type Type = u8;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inb %dx, %al" : "={al}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u8> {
    type Type = u8;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outb %al, %dx" :  : "{al}"(data), "{dx}"(self.num) :  : "volatile");
    }
}

impl<Out> InPort for IOPort<u16, Out> {
    type Type = u16;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inw %dx, %ax" : "={ax}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u16> {
    type Type = u16;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outw %ax, %dx" :  : "{ax}"(data), "{dx}"(self.num) :  : "volatile");
    }
}

impl<Out> InPort for IOPort<u32, Out> {
    type Type = u32;

    unsafe fn read(&mut self) -> Self::Type {
        let ret: Self::Type;
        asm!("inl %dx, %eax" : "={eax}"(ret) : "{dx}"(self.num) :  : "volatile");
        ret
    }
}

impl<In> OutPort for IOPort<In, u32> {
    type Type = u32;

    unsafe fn write(&mut self, data: Self::Type) {
        asm!("outl %eax, %dx" :  : "{eax}"(data), "{dx}"(self.num) :  : "volatile");
    }
}
<|endoftext|>