<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Marvin Böcker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! This module contains the most important struct of this crate: The Certificate
//! It holds a public key, meta data and a signature.
//! It can also optionally hold a private key and sign data.

use bytescontainer::BytesContainer;
use meta::Meta;
use signature::Signature;
use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::Decoder;
use chrono;
use ed25519;
use certificate_validator::Validatable;

/// This is the length of a ed25519 signature.
pub const SIGNATURE_LEN: usize = 64 + CERTIFICATE_BYTE_LEN;

/// This is the length of a ed25519 private key.
pub const PRIVATE_KEY_LEN: usize = ed25519::PRIVATE_KEY_LEN;

/// This is the length of a ed25519 public key.
pub const PUBLIC_KEY_LEN: usize = ed25519::PUBLIC_KEY_LEN;

/// This is the length of a safehash of a certificate.
pub const CERTIFICATE_BYTE_LEN: usize =
    25 /* expires as string */ + 64 /* hash of meta */ + PUBLIC_KEY_LEN;

/// A certificate holds a public key, meta data and a signature.
///
/// 1. It can be randomly generated by using the generate_random() method.
/// 2. It can then be signed using the sign_with_master and sign_certificate methods.
/// 3. It can then be used to sign data / certificates by using the sign / sign_certificate
/// methods.
/// 4. Data can be verified by using the verify method.
/// 5. A Certificate can be validated by a CertificateValidator, because it implements the
/// Validatable trait.
#[derive(Clone,RustcDecodable,RustcEncodable,Debug)]
pub struct Certificate {
    /// The meta element contains data associated with the certificate.
    /// Common data is "use-for" which contains a list of permissions.
    meta: Meta,

    /// the public key of this certificate.
    public_key: BytesContainer,

    /// the private key, if it is known.
    private_key: Option<BytesContainer>,

    /// a timestamp when this certificate expires.
    expires: String,

    /// a signature for trust-chaining certificates
    /// if the certificate is not signed yet, this is None
    signature: Option<Signature>,
}

impl Certificate {
    /// This method generates a random public/private keypair and a certificate for it.
    pub fn generate_random(meta: Meta, expires: chrono::DateTime<chrono::UTC>) -> Certificate {
        // generate a keypair. this returns two arrays
        let (pubslice, prvslice) = ed25519::generate_keypair();

        // convert the arrays to vectors
        let mut public_key = Vec::new();
        let mut private_key = Vec::new();

        public_key.extend_from_slice(&pubslice[..]);
        private_key.extend_from_slice(&prvslice[..]);

        // create the certificate
        Certificate {
            private_key: Some(BytesContainer::new(private_key)),
            public_key: BytesContainer::new(public_key),
            expires: expires.to_rfc3339(),
            meta: meta,
            signature: None,
        }
    }

    /// This method returns a mutable reference to the meta structure.
    pub fn meta_mut(&mut self) -> &mut Meta {
        &mut self.meta
    }

    /// This method returns a reference to the meta structure.
    pub fn meta(&self) -> &Meta {
        &self.meta
    }

    /// This method returns a reference to the public key.
    pub fn public_key(&self) -> &Vec<u8> {
        &self.public_key.get()
    }

    /// This method returns the private key, if it is known, or None if the certificate has been
    /// initialized without the private key.
    pub fn private_key<'a>(&'a self) -> Option<&'a Vec<u8>> {
        if self.has_private_key() {
            let vec = self.private_key.as_ref().unwrap().get();
            Some(vec)
        } else {
            None
        }
    }

    /// This method returns true, if the private key is saved in the certificate.
    pub fn has_private_key(&self) -> bool {
        self.private_key.is_some()
    }

    /// This method returns the expiration date as a RFC 3339 string.
    pub fn expiration_date(&self) -> &str {
        &self.expires
    }

    /// This method returns either the signature, or None.
    pub fn signature(&self) -> Option<&Signature> {
        self.signature.as_ref()
    }

    /// This method replaces the current private key of this certificate with the given one.
    pub fn set_private_key(&mut self, private_key: Vec<u8>) {
        self.private_key = Some(BytesContainer::new(private_key));
    }

    /// This method checks, if the "use-for" meta tag contains the use "edcert.sign"
    pub fn can_sign(&self) -> Result<(), &'static str> {
        use rustc_serialize::json;

        let meta = self.meta();

        println!("meta: {:?}", meta);

        match meta.get("use-for") {
            Some(use_for) => {
                let use_for: Vec<String> = match json::decode(use_for) {
                    Ok(x) => x,
                    Err(_) => {
                        return Err("Failed to parse content of meta value \"use-for\"");
                    }
                };

                for u in use_for {
                    println!("{} ?= edcert.sign?", u);
                    if u == "edcert.sign" {
                        return Ok(());
                    }
                }

                Err("This certificate is not allowed to sign certificates")
            }
            None => Err("The meta value \"use-for\" could not be found"),
        }
    }

    /// This method returns a "hash". This is used to validate the certificate.
    /// All relevant information of the certificate is used to produce the hash,
    /// including the public key, meta data and the expiration date.
    pub fn safehash(&self) -> [u8; CERTIFICATE_BYTE_LEN] {

        // create a array of this length
        let mut bytes = [0; CERTIFICATE_BYTE_LEN];

        // first 64 bytes are a sha512 hash of meta. the ordering of meta entries is irrelevant
        self.meta.fill_bytes(&mut bytes[0..64]);

        // next 25 bytes are string representation of the expiration string
        ::copy_bytes(&mut bytes[64..], self.expires.as_bytes(), 0, 0, 25);

        // finally, the public key is appended
        ::copy_bytes(&mut bytes[89..],
                     &self.public_key.get()[..],
                     0,
                     0,
                     PUBLIC_KEY_LEN);

        bytes
    }

    /// This method returns the parent certificate of this certificate, if it exists.
    pub fn parent(&self) -> Option<&Certificate> {
        if self.is_signed() {
            let sig = &self.signature.as_ref().unwrap();
            sig.parent()
        } else {
            None
        }
    }

    /// This method returns true, if a signature exists (is not None). This doesn't validate the
    /// signature.
    pub fn is_signed(&self) -> bool {
        self.signature.is_some()
    }

    /// This method signs the given data and returns the signature.
    pub fn sign(&self, data: &[u8]) -> Option<Vec<u8>> {
        if self.has_private_key() {
            let signature = ed25519::sign(data, self.private_key().unwrap());
            Some(signature)
        } else {
            None
        }
    }

    /// This method signs this certificate with the given private master key.
    pub fn sign_with_master(&mut self, master_private_key: &[u8]) {
        let bytes = self.safehash();
        let hash = ed25519::sign(&bytes[..], master_private_key);
        self.signature = Some(Signature::new(hash));
    }

    /// This method signs another certificate with the private key of this certificate.
    pub fn sign_certificate(&self, other: &mut Certificate) -> Result<(), &'static str> {
        if self.has_private_key() {
            let child_bytes = other.safehash();
            let signature_bytes = self.sign(&child_bytes).unwrap().to_vec();
            let parent = Box::new(self.clone());
            let signature = Signature::with_parent(parent, signature_bytes);

            other.signature = Some(signature);

            Ok(())
        } else {
            Err("This certificate has no private key")
        }
    }

    /// This method checks, if this certificates expiration date is now or in the past.
    pub fn is_expired(&self) -> bool {

        // try to parse the string of this certificate
        let expires = match chrono::DateTime::parse_from_rfc3339(&self.expires) {
            Err(_) => return true,
            Ok(expires) => expires.with_timezone(&chrono::UTC),
        };

        // if the parsing is ok, then this must be true for the certificate to be expired
        expires <= chrono::UTC::now()
    }

    /// This method verifies that the given signature is valid for the given data.
    pub fn verify(&self, data: &[u8], signature: &[u8]) -> bool {
        let result = ed25519::verify(data, signature, self.public_key());
        result
    }
}

impl Validatable for Certificate {
    fn is_valid(&self, master_pk: &[u8]) -> Result<(), &'static str> {
        if !self.is_signed() {
            Err("This certificate isn't signed, so it can't be valid.")
        } else {

            // get a hash unique to this certificate
            let bytes: &[u8] = &self.safehash()[..];

            // get the signature
            let signature = self.signature.as_ref().unwrap();

            // if it is signed by the master key
            if signature.is_signed_by_master() {

                // get the signature hash
                let hash = signature.hash();

                // verify it for the safehash, master public key and the signature
                let r = ed25519::verify(bytes, hash, master_pk);

                // if it is valid
                if r {

                    // check if the certificate is expired
                    if self.is_expired() {
                        Err("This certificate is expired")
                    } else {
                        Ok(())
                    }

                } else {

                    // else the signature isn't from the master key
                    Err("Failed to verify master signature")
                }

            } else {

                // if it is not signed by the master key, get the parent
                let parent: &Certificate = signature.parent().unwrap();

                // verify the signature of the parent
                let sign_real = parent.verify(bytes, &signature.hash());

                // verify that the parent is valid
                let parent_real = parent.is_valid(&master_pk).is_ok();

                // can parent sign other certificates?
                let parent_can_sign = parent.can_sign().is_ok();

                // if the signature is valid
                if sign_real {

                    // and the parent certificate is valid
                    if parent_real {

                        // and the parent can sign
                        if parent_can_sign {

                            // and the certificate is not expired
                            if !self.is_expired() {
                                Ok(())
                            } else {
                                Err("The certificate is expired")
                            }

                        } else {
                            Err("The parent isn't allowed to sign certificates.")
                        }

                    } else {
                        Err("The parent is invalid.")
                    }
                } else {
                    Err("The signature of the parent isn invalid.")
                }
            }
        }
    }

    fn is_revokable(&self) -> bool {
        true
    }

    fn get_id(&self) -> String {
        self.public_key.to_bytestr()
    }
}

#[test]
fn test_generate_certificate() {
    use chrono::Timelike;
    use chrono::UTC;
    use time::Duration;

    let meta = Meta::new_empty();
    let expires = UTC::now()
                      .checked_add(Duration::days(90))
                      .expect("Failed to add a day to expiration date.")
                      .with_nanosecond(0)
                      .unwrap();

    let a = Certificate::generate_random(meta, expires);

    let meta = Meta::new_empty();

    let b = Certificate::generate_random(meta, expires);

    assert!(a.public_key() != b.public_key());
}

// #[test]
// fn test_revoke() {
//     use chrono::Timelike;
//     use chrono::UTC;
//     use time::Duration;
//
//     let meta = Meta::new_empty();
//     let expires = UTC::now()
//                       .checked_add(Duration::days(90))
//                       .expect("Failed to add 90 days to expiration date.")
//                       .with_nanosecond(0)
//                       .unwrap();
//     let cert = Certificate::generate_random(meta, expires);
//
//     cert.is_revoked("http://localhost/api.php").is_err();
// }
<commit_msg>Removed debug output<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Marvin Böcker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! This module contains the most important struct of this crate: The Certificate
//! It holds a public key, meta data and a signature.
//! It can also optionally hold a private key and sign data.

use bytescontainer::BytesContainer;
use meta::Meta;
use signature::Signature;
use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::Decoder;
use chrono;
use ed25519;
use certificate_validator::Validatable;

/// This is the length of a ed25519 signature.
pub const SIGNATURE_LEN: usize = 64 + CERTIFICATE_BYTE_LEN;

/// This is the length of a ed25519 private key.
pub const PRIVATE_KEY_LEN: usize = ed25519::PRIVATE_KEY_LEN;

/// This is the length of a ed25519 public key.
pub const PUBLIC_KEY_LEN: usize = ed25519::PUBLIC_KEY_LEN;

/// This is the length of a safehash of a certificate.
pub const CERTIFICATE_BYTE_LEN: usize =
    25 /* expires as string */ + 64 /* hash of meta */ + PUBLIC_KEY_LEN;

/// A certificate holds a public key, meta data and a signature.
///
/// 1. It can be randomly generated by using the generate_random() method.
/// 2. It can then be signed using the sign_with_master and sign_certificate methods.
/// 3. It can then be used to sign data / certificates by using the sign / sign_certificate
/// methods.
/// 4. Data can be verified by using the verify method.
/// 5. A Certificate can be validated by a CertificateValidator, because it implements the
/// Validatable trait.
#[derive(Clone,RustcDecodable,RustcEncodable,Debug)]
pub struct Certificate {
    /// The meta element contains data associated with the certificate.
    /// Common data is "use-for" which contains a list of permissions.
    meta: Meta,

    /// the public key of this certificate.
    public_key: BytesContainer,

    /// the private key, if it is known.
    private_key: Option<BytesContainer>,

    /// a timestamp when this certificate expires.
    expires: String,

    /// a signature for trust-chaining certificates
    /// if the certificate is not signed yet, this is None
    signature: Option<Signature>,
}

impl Certificate {
    /// This method generates a random public/private keypair and a certificate for it.
    pub fn generate_random(meta: Meta, expires: chrono::DateTime<chrono::UTC>) -> Certificate {
        // generate a keypair. this returns two arrays
        let (pubslice, prvslice) = ed25519::generate_keypair();

        // convert the arrays to vectors
        let mut public_key = Vec::new();
        let mut private_key = Vec::new();

        public_key.extend_from_slice(&pubslice[..]);
        private_key.extend_from_slice(&prvslice[..]);

        // create the certificate
        Certificate {
            private_key: Some(BytesContainer::new(private_key)),
            public_key: BytesContainer::new(public_key),
            expires: expires.to_rfc3339(),
            meta: meta,
            signature: None,
        }
    }

    /// This method returns a mutable reference to the meta structure.
    pub fn meta_mut(&mut self) -> &mut Meta {
        &mut self.meta
    }

    /// This method returns a reference to the meta structure.
    pub fn meta(&self) -> &Meta {
        &self.meta
    }

    /// This method returns a reference to the public key.
    pub fn public_key(&self) -> &Vec<u8> {
        &self.public_key.get()
    }

    /// This method returns the private key, if it is known, or None if the certificate has been
    /// initialized without the private key.
    pub fn private_key<'a>(&'a self) -> Option<&'a Vec<u8>> {
        if self.has_private_key() {
            let vec = self.private_key.as_ref().unwrap().get();
            Some(vec)
        } else {
            None
        }
    }

    /// This method returns true, if the private key is saved in the certificate.
    pub fn has_private_key(&self) -> bool {
        self.private_key.is_some()
    }

    /// This method returns the expiration date as a RFC 3339 string.
    pub fn expiration_date(&self) -> &str {
        &self.expires
    }

    /// This method returns either the signature, or None.
    pub fn signature(&self) -> Option<&Signature> {
        self.signature.as_ref()
    }

    /// This method replaces the current private key of this certificate with the given one.
    pub fn set_private_key(&mut self, private_key: Vec<u8>) {
        self.private_key = Some(BytesContainer::new(private_key));
    }

    /// This method checks, if the "use-for" meta tag contains the use "edcert.sign"
    pub fn can_sign(&self) -> Result<(), &'static str> {
        use rustc_serialize::json;

        let meta = self.meta();

        match meta.get("use-for") {
            Some(use_for) => {
                let use_for: Vec<String> = match json::decode(use_for) {
                    Ok(x) => x,
                    Err(_) => {
                        return Err("Failed to parse content of meta value \"use-for\"");
                    }
                };

                for u in use_for {
                    if u == "edcert.sign" {
                        return Ok(());
                    }
                }

                Err("This certificate is not allowed to sign certificates")
            }
            None => Err("The meta value \"use-for\" could not be found"),
        }
    }

    /// This method returns a "hash". This is used to validate the certificate.
    /// All relevant information of the certificate is used to produce the hash,
    /// including the public key, meta data and the expiration date.
    pub fn safehash(&self) -> [u8; CERTIFICATE_BYTE_LEN] {

        // create a array of this length
        let mut bytes = [0; CERTIFICATE_BYTE_LEN];

        // first 64 bytes are a sha512 hash of meta. the ordering of meta entries is irrelevant
        self.meta.fill_bytes(&mut bytes[0..64]);

        // next 25 bytes are string representation of the expiration string
        ::copy_bytes(&mut bytes[64..], self.expires.as_bytes(), 0, 0, 25);

        // finally, the public key is appended
        ::copy_bytes(&mut bytes[89..],
                     &self.public_key.get()[..],
                     0,
                     0,
                     PUBLIC_KEY_LEN);

        bytes
    }

    /// This method returns the parent certificate of this certificate, if it exists.
    pub fn parent(&self) -> Option<&Certificate> {
        if self.is_signed() {
            let sig = &self.signature.as_ref().unwrap();
            sig.parent()
        } else {
            None
        }
    }

    /// This method returns true, if a signature exists (is not None). This doesn't validate the
    /// signature.
    pub fn is_signed(&self) -> bool {
        self.signature.is_some()
    }

    /// This method signs the given data and returns the signature.
    pub fn sign(&self, data: &[u8]) -> Option<Vec<u8>> {
        if self.has_private_key() {
            let signature = ed25519::sign(data, self.private_key().unwrap());
            Some(signature)
        } else {
            None
        }
    }

    /// This method signs this certificate with the given private master key.
    pub fn sign_with_master(&mut self, master_private_key: &[u8]) {
        let bytes = self.safehash();
        let hash = ed25519::sign(&bytes[..], master_private_key);
        self.signature = Some(Signature::new(hash));
    }

    /// This method signs another certificate with the private key of this certificate.
    pub fn sign_certificate(&self, other: &mut Certificate) -> Result<(), &'static str> {
        if self.has_private_key() {
            let child_bytes = other.safehash();
            let signature_bytes = self.sign(&child_bytes).unwrap().to_vec();
            let parent = Box::new(self.clone());
            let signature = Signature::with_parent(parent, signature_bytes);

            other.signature = Some(signature);

            Ok(())
        } else {
            Err("This certificate has no private key")
        }
    }

    /// This method checks, if this certificates expiration date is now or in the past.
    pub fn is_expired(&self) -> bool {

        // try to parse the string of this certificate
        let expires = match chrono::DateTime::parse_from_rfc3339(&self.expires) {
            Err(_) => return true,
            Ok(expires) => expires.with_timezone(&chrono::UTC),
        };

        // if the parsing is ok, then this must be true for the certificate to be expired
        expires <= chrono::UTC::now()
    }

    /// This method verifies that the given signature is valid for the given data.
    pub fn verify(&self, data: &[u8], signature: &[u8]) -> bool {
        let result = ed25519::verify(data, signature, self.public_key());
        result
    }
}

impl Validatable for Certificate {
    fn is_valid(&self, master_pk: &[u8]) -> Result<(), &'static str> {
        if !self.is_signed() {
            Err("This certificate isn't signed, so it can't be valid.")
        } else {

            // get a hash unique to this certificate
            let bytes: &[u8] = &self.safehash()[..];

            // get the signature
            let signature = self.signature.as_ref().unwrap();

            // if it is signed by the master key
            if signature.is_signed_by_master() {

                // get the signature hash
                let hash = signature.hash();

                // verify it for the safehash, master public key and the signature
                let r = ed25519::verify(bytes, hash, master_pk);

                // if it is valid
                if r {

                    // check if the certificate is expired
                    if self.is_expired() {
                        Err("This certificate is expired")
                    } else {
                        Ok(())
                    }

                } else {

                    // else the signature isn't from the master key
                    Err("Failed to verify master signature")
                }

            } else {

                // if it is not signed by the master key, get the parent
                let parent: &Certificate = signature.parent().unwrap();

                // verify the signature of the parent
                let sign_real = parent.verify(bytes, &signature.hash());

                // verify that the parent is valid
                let parent_real = parent.is_valid(&master_pk).is_ok();

                // can parent sign other certificates?
                let parent_can_sign = parent.can_sign().is_ok();

                // if the signature is valid
                if sign_real {

                    // and the parent certificate is valid
                    if parent_real {

                        // and the parent can sign
                        if parent_can_sign {

                            // and the certificate is not expired
                            if !self.is_expired() {
                                Ok(())
                            } else {
                                Err("The certificate is expired")
                            }
                        } else {
                            Err("The parent isn't allowed to sign certificates.")
                        }
                    } else {
                        Err("The parent is invalid.")
                    }
                } else {
                    Err("The signature of the parent isn invalid.")
                }
            }
        }
    }

    fn is_revokable(&self) -> bool {
        true
    }

    fn get_id(&self) -> String {
        self.public_key.to_bytestr()
    }
}

#[test]
fn test_generate_certificate() {
    use chrono::Timelike;
    use chrono::UTC;
    use time::Duration;

    let meta = Meta::new_empty();
    let expires = UTC::now()
                      .checked_add(Duration::days(90))
                      .expect("Failed to add a day to expiration date.")
                      .with_nanosecond(0)
                      .unwrap();

    let a = Certificate::generate_random(meta, expires);

    let meta = Meta::new_empty();

    let b = Certificate::generate_random(meta, expires);

    assert!(a.public_key() != b.public_key());
}

// #[test]
// fn test_revoke() {
//     use chrono::Timelike;
//     use chrono::UTC;
//     use time::Duration;
//
//     let meta = Meta::new_empty();
//     let expires = UTC::now()
//                       .checked_add(Duration::days(90))
//                       .expect("Failed to add 90 days to expiration date.")
//                       .with_nanosecond(0)
//                       .unwrap();
//     let cert = Certificate::generate_random(meta, expires);
//
//     cert.is_revoked("http://localhost/api.php").is_err();
// }
<|endoftext|>


<commit_before>use crate::location::Location;
use crate::map::Map;
use crate::spec::{self, EntitySpawn};
use crate::terrain::Terrain;
use crate::vaults;
use crate::{Distribution, Rng};
use calx::{self, die, CellVector, RngExt, WeightedChoice};
use euclid::{vec3, Vector3D};
use log::{debug, warn};
use rand::seq::SliceRandom;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::ops::{Add, Deref, DerefMut};
use std::str::FromStr;
use std::sync::Arc;

pub const SECTOR_WIDTH: i32 = 38;
pub const SECTOR_HEIGHT: i32 = 18;

pub struct SectorSpace;
pub type SectorVector = Vector3D<i16, SectorSpace>;

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i16,
    pub y: i16,
    pub z: i16,
}

impl Add<SectorVector> for Sector {
    type Output = Sector;
    fn add(self, other: SectorVector) -> Sector {
        Sector {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sector {
    pub const fn new(x: i16, y: i16, z: i16) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    pub fn iter(self) -> impl Iterator<Item = Location> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        (0..n).map(move |i| self.rect_coord_loc(i % pitch, i / pitch))
    }

    /// Iterate offset points for a generic `Sector`.
    pub fn points() -> impl Iterator<Item = CellVector> {
        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        sector
            .iter()
            .map(move |loc| sector_origin.v2_at(loc).unwrap())
    }

    pub fn taxicab_distance(self, other: Sector) -> i32 {
        ((self.x as i32) - (other.x as i32)).abs()
            + ((self.y as i32) - (other.y as i32)).abs()
            + ((self.z as i32) - (other.z as i32)).abs()
    }
}

/// Specification for generating a Sector's map.
///
/// This serves as the top-level entry point to map generation routines.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SectorSpec {
    // TODO: Sectors can be predefined maps.
    // TODO: flags for blocked connection to N,E,W,S,up and down neighbor sectors
    // By default create path/stairs if adjacent sector exists.
    pub depth: i32,
    // TODO: Terrain variants, dungeon, overland etc.
}

impl SectorSpec {
    /// Return the terrain that unfilled areas on this sector should be.
    pub fn default_terrain(&self) -> Terrain {
        // TODO: Different terrain for overland cells
        Terrain::Rock
    }
}

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct WorldSkeleton(HashMap<Sector, SectorSpec>);

impl Deref for WorldSkeleton {
    type Target = HashMap<Sector, SectorSpec>;

    fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for WorldSkeleton {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl WorldSkeleton {
    pub fn dungeon_dive() -> WorldSkeleton {
        let mut ret = WorldSkeleton::default();
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16));
            let spec = SectorSpec { depth };
            ret.insert(sector, spec);
        }
        ret
    }
}

/// Generate the map for a sector given the 3D world skeleton.
///
/// Note that this function does not take a rng. The idea is that map generation should be
/// perfectly deterministic given a world seed and the sector position, so new sectors can be
/// lazily generated at any point of the game.
pub fn generate<'a>(seed: u32, pos: Sector, world_skeleton: &WorldSkeleton) -> Map {
    ConnectedSectorSpec::new(pos, world_skeleton).sample(&mut calx::seeded_rng(&(seed, pos)))
}

/// Wrapper for `SectorSpec` with references to neighboring sectors.
///
/// This is needed for map generation where connections or terrain transition tiles on the edge
/// will be placed based on the neighboring sectors. Map generation will try to build connective
/// pathways to traversable neighboring sectors unless the central spec specifically forbids it.
pub struct ConnectedSectorSpec<'a> {
    pub spec: &'a SectorSpec,
    pub north: Option<&'a SectorSpec>,
    pub east: Option<&'a SectorSpec>,
    pub south: Option<&'a SectorSpec>,
    pub west: Option<&'a SectorSpec>,
    pub up: Option<&'a SectorSpec>,
    pub down: Option<&'a SectorSpec>,
}

impl<'a> ConnectedSectorSpec<'a> {
    pub fn new(spec_location: Sector, world_skeleton: &'a WorldSkeleton) -> Self {
        ConnectedSectorSpec {
            spec: world_skeleton.get(&spec_location).unwrap(),
            north: world_skeleton.get(&(spec_location + vec3(0, -1, 0))),
            east: world_skeleton.get(&(spec_location + vec3(1, 0, 0))),
            south: world_skeleton.get(&(spec_location + vec3(0, 1, 0))),
            west: world_skeleton.get(&(spec_location + vec3(-1, 0, 0))),
            up: world_skeleton.get(&(spec_location + vec3(0, 0, 1))),
            down: world_skeleton.get(&(spec_location + vec3(0, 0, -1))),
        }
    }
}

impl<'a> Deref for ConnectedSectorSpec<'a> {
    type Target = SectorSpec;

    fn deref(&self) -> &SectorSpec { self.spec }
}

impl<'a> Distribution<Map> for ConnectedSectorSpec<'a> {
    fn sample(&self, rng: &mut Rng) -> Map {
        // TODO: Switch between different biomes, do more than just the default dungeon.
        self.build_dungeon(rng)
    }
}

impl<'a> ConnectedSectorSpec<'a> {
    fn dungeon_gen(&self, rng: &mut Rng) -> Result<Map, Box<dyn Error>> {
        // TODO: Connect to side levels if they exist

        debug!("Starting mapgen");
        let mut map = self.new_map();

        if self.up.is_some() {
            let room: Entrance = self.sample(rng);
            debug!("Placing upstairs");
            map.place_room(rng, &*room.0)?;
        }

        loop {
            let room: Room = self.sample(rng);
            debug!("Adding room");
            if map.place_room(rng, &*room.0).is_err() {
                break;
            }
        }

        if self.down.is_some() {
            debug!("Placing downstairs");
            let room = vaults::EXITS.choose(rng).unwrap();
            map.place_room(rng, &*room)?;
        }

        if let Some(map) = map.join_disjoint_regions(rng) {
            Ok(map)
        } else {
            die!("Failed to join map");
        }
    }

    fn build_dungeon(&self, rng: &mut Rng) -> Map {
        const NUM_RETRIES: usize = 16;

        if let Ok(map) = calx::retry_gen(NUM_RETRIES, rng, |rng| self.dungeon_gen(rng)) {
            map
        } else {
            // Fallback, couldn't generate map, let's do something foolproof.
            warn!("Repeated dungeon generation failure, falling back to bigroom");
            self.build_bigroom(rng)
        }
    }

    fn build_bigroom(&self, rng: &mut Rng) -> Map {
        let mut map = self.new_map();
        for p in map.find_positions(|_, _| true) {
            map.dig(p);
        }

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn new_map(&self) -> Map {
        Map::new_base(
            Sector::points()
                .filter(|p| !Location::new(p.x as i16, p.y as i16, 0).is_next_to_diagonal_sector()),
        )
    }
}

impl Distribution<EntitySpawn> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> EntitySpawn {
        let item = spec::iter_specs()
            .weighted_choice(rng, |item| {
                if item.rarity() == 0.0 || item.min_depth() > self.depth {
                    0.0
                } else {
                    1.0 / item.rarity()
                }
            })
            .unwrap();

        EntitySpawn::from_str(item.name()).unwrap()
    }
}

/// Include spawn density of entities, can be run over all open cells.
///
/// XXX: You maybe want something smarter than this to handle clustering of mobs etc.
impl Distribution<Option<EntitySpawn>> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Option<EntitySpawn> {
        if rng.one_chance_in(10) {
            Some(self.sample(rng))
        } else {
            None
        }
    }
}

struct Entrance(Arc<Map>);

impl Distribution<Entrance> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Entrance {
        Entrance(vaults::ENTRANCES.choose(rng).unwrap().clone())
    }
}

struct Room(Arc<Map>);

impl Distribution<Room> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Room {
        if rng.one_chance_in(12) {
            // Make a vault sometimes.
            Room(vaults::VAULTS.choose(rng).unwrap().clone())
        } else {
            // Make a procgen room normally.
            let mut map = Map::new_plain_room(rng);
            for &pos in &map.open_ground() {
                if let Some(spawn) = self.sample(rng) {
                    map.push_spawn(pos, spawn);
                }
            }

            Room(Arc::new(map))
        }
    }
}

struct Exit(Arc<Map>);

impl Distribution<Exit> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Exit { Exit(vaults::EXITS.choose(rng).unwrap().clone()) }
}
<commit_msg>Restore original sector size<commit_after>use crate::location::Location;
use crate::map::Map;
use crate::spec::{self, EntitySpawn};
use crate::terrain::Terrain;
use crate::vaults;
use crate::{Distribution, Rng};
use calx::{self, die, CellVector, RngExt, WeightedChoice};
use euclid::{vec3, Vector3D};
use log::{debug, warn};
use rand::seq::SliceRandom;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::ops::{Add, Deref, DerefMut};
use std::str::FromStr;
use std::sync::Arc;

pub const SECTOR_WIDTH: i32 = 40;
pub const SECTOR_HEIGHT: i32 = 20;

pub struct SectorSpace;
pub type SectorVector = Vector3D<i16, SectorSpace>;

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i16,
    pub y: i16,
    pub z: i16,
}

impl Add<SectorVector> for Sector {
    type Output = Sector;
    fn add(self, other: SectorVector) -> Sector {
        Sector {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sector {
    pub const fn new(x: i16, y: i16, z: i16) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    pub fn iter(self) -> impl Iterator<Item = Location> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        (0..n).map(move |i| self.rect_coord_loc(i % pitch, i / pitch))
    }

    /// Iterate offset points for a generic `Sector`.
    pub fn points() -> impl Iterator<Item = CellVector> {
        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        sector
            .iter()
            .map(move |loc| sector_origin.v2_at(loc).unwrap())
    }

    pub fn taxicab_distance(self, other: Sector) -> i32 {
        ((self.x as i32) - (other.x as i32)).abs()
            + ((self.y as i32) - (other.y as i32)).abs()
            + ((self.z as i32) - (other.z as i32)).abs()
    }
}

/// Specification for generating a Sector's map.
///
/// This serves as the top-level entry point to map generation routines.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SectorSpec {
    // TODO: Sectors can be predefined maps.
    // TODO: flags for blocked connection to N,E,W,S,up and down neighbor sectors
    // By default create path/stairs if adjacent sector exists.
    pub depth: i32,
    // TODO: Terrain variants, dungeon, overland etc.
}

impl SectorSpec {
    /// Return the terrain that unfilled areas on this sector should be.
    pub fn default_terrain(&self) -> Terrain {
        // TODO: Different terrain for overland cells
        Terrain::Rock
    }
}

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct WorldSkeleton(HashMap<Sector, SectorSpec>);

impl Deref for WorldSkeleton {
    type Target = HashMap<Sector, SectorSpec>;

    fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for WorldSkeleton {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl WorldSkeleton {
    pub fn dungeon_dive() -> WorldSkeleton {
        let mut ret = WorldSkeleton::default();
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16));
            let spec = SectorSpec { depth };
            ret.insert(sector, spec);
        }
        ret
    }
}

/// Generate the map for a sector given the 3D world skeleton.
///
/// Note that this function does not take a rng. The idea is that map generation should be
/// perfectly deterministic given a world seed and the sector position, so new sectors can be
/// lazily generated at any point of the game.
pub fn generate<'a>(seed: u32, pos: Sector, world_skeleton: &WorldSkeleton) -> Map {
    ConnectedSectorSpec::new(pos, world_skeleton).sample(&mut calx::seeded_rng(&(seed, pos)))
}

/// Wrapper for `SectorSpec` with references to neighboring sectors.
///
/// This is needed for map generation where connections or terrain transition tiles on the edge
/// will be placed based on the neighboring sectors. Map generation will try to build connective
/// pathways to traversable neighboring sectors unless the central spec specifically forbids it.
pub struct ConnectedSectorSpec<'a> {
    pub spec: &'a SectorSpec,
    pub north: Option<&'a SectorSpec>,
    pub east: Option<&'a SectorSpec>,
    pub south: Option<&'a SectorSpec>,
    pub west: Option<&'a SectorSpec>,
    pub up: Option<&'a SectorSpec>,
    pub down: Option<&'a SectorSpec>,
}

impl<'a> ConnectedSectorSpec<'a> {
    pub fn new(spec_location: Sector, world_skeleton: &'a WorldSkeleton) -> Self {
        ConnectedSectorSpec {
            spec: world_skeleton.get(&spec_location).unwrap(),
            north: world_skeleton.get(&(spec_location + vec3(0, -1, 0))),
            east: world_skeleton.get(&(spec_location + vec3(1, 0, 0))),
            south: world_skeleton.get(&(spec_location + vec3(0, 1, 0))),
            west: world_skeleton.get(&(spec_location + vec3(-1, 0, 0))),
            up: world_skeleton.get(&(spec_location + vec3(0, 0, 1))),
            down: world_skeleton.get(&(spec_location + vec3(0, 0, -1))),
        }
    }
}

impl<'a> Deref for ConnectedSectorSpec<'a> {
    type Target = SectorSpec;

    fn deref(&self) -> &SectorSpec { self.spec }
}

impl<'a> Distribution<Map> for ConnectedSectorSpec<'a> {
    fn sample(&self, rng: &mut Rng) -> Map {
        // TODO: Switch between different biomes, do more than just the default dungeon.
        self.build_dungeon(rng)
    }
}

impl<'a> ConnectedSectorSpec<'a> {
    fn dungeon_gen(&self, rng: &mut Rng) -> Result<Map, Box<dyn Error>> {
        // TODO: Connect to side levels if they exist

        debug!("Starting mapgen");
        let mut map = self.new_map();

        if self.up.is_some() {
            let room: Entrance = self.sample(rng);
            debug!("Placing upstairs");
            map.place_room(rng, &*room.0)?;
        }

        loop {
            let room: Room = self.sample(rng);
            debug!("Adding room");
            if map.place_room(rng, &*room.0).is_err() {
                break;
            }
        }

        if self.down.is_some() {
            debug!("Placing downstairs");
            let room = vaults::EXITS.choose(rng).unwrap();
            map.place_room(rng, &*room)?;
        }

        if let Some(map) = map.join_disjoint_regions(rng) {
            Ok(map)
        } else {
            die!("Failed to join map");
        }
    }

    fn build_dungeon(&self, rng: &mut Rng) -> Map {
        const NUM_RETRIES: usize = 16;

        if let Ok(map) = calx::retry_gen(NUM_RETRIES, rng, |rng| self.dungeon_gen(rng)) {
            map
        } else {
            // Fallback, couldn't generate map, let's do something foolproof.
            warn!("Repeated dungeon generation failure, falling back to bigroom");
            self.build_bigroom(rng)
        }
    }

    fn build_bigroom(&self, rng: &mut Rng) -> Map {
        let mut map = self.new_map();
        for p in map.find_positions(|_, _| true) {
            map.dig(p);
        }

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn new_map(&self) -> Map {
        Map::new_base(
            Sector::points()
                .filter(|p| !Location::new(p.x as i16, p.y as i16, 0).is_next_to_diagonal_sector()),
        )
    }
}

impl Distribution<EntitySpawn> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> EntitySpawn {
        let item = spec::iter_specs()
            .weighted_choice(rng, |item| {
                if item.rarity() == 0.0 || item.min_depth() > self.depth {
                    0.0
                } else {
                    1.0 / item.rarity()
                }
            })
            .unwrap();

        EntitySpawn::from_str(item.name()).unwrap()
    }
}

/// Include spawn density of entities, can be run over all open cells.
///
/// XXX: You maybe want something smarter than this to handle clustering of mobs etc.
impl Distribution<Option<EntitySpawn>> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Option<EntitySpawn> {
        if rng.one_chance_in(10) {
            Some(self.sample(rng))
        } else {
            None
        }
    }
}

struct Entrance(Arc<Map>);

impl Distribution<Entrance> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Entrance {
        Entrance(vaults::ENTRANCES.choose(rng).unwrap().clone())
    }
}

struct Room(Arc<Map>);

impl Distribution<Room> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Room {
        if rng.one_chance_in(12) {
            // Make a vault sometimes.
            Room(vaults::VAULTS.choose(rng).unwrap().clone())
        } else {
            // Make a procgen room normally.
            let mut map = Map::new_plain_room(rng);
            for &pos in &map.open_ground() {
                if let Some(spawn) = self.sample(rng) {
                    map.push_spawn(pos, spawn);
                }
            }

            Room(Arc::new(map))
        }
    }
}

struct Exit(Arc<Map>);

impl Distribution<Exit> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Exit { Exit(vaults::EXITS.choose(rng).unwrap().clone()) }
}
<|endoftext|>


<commit_before>use syntax::{
    ast::{self, HasStringValue},
    AstToken,
    SyntaxKind::STRING,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: replace_string_with_char
//
// Replace string with char.
//
// ```
// fn main() {
//     find("{<|>");
// }
// ```
// ->
// ```
// fn main() {
//     find('{');
// }
// ```
pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();

    if value.is_empty() || value.chars().count() > 1 {
        return None;
    }

    acc.add(
        AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
        "Replace string with char",
        target,
        |edit| {
            edit.replace(token.syntax().text_range(), format!("'{}'", value));
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn replace_string_with_char_target() {
        check_assist_target(
            replace_string_with_char,
            r#"
            fn f() {
                let s = "<|>c";
            }
            "#,
            r#""c""#,
        );
    }

    #[test]
    fn replace_string_with_char_assist() {
        check_assist(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "<|>c";
    }
    "#,
            r##"
    fn f() {
        let s = 'c';
    }
    "##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_with_emoji() {
        check_assist(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "<|>😀";
    }
    "#,
            r##"
    fn f() {
        let s = '😀';
    }
    "##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_not_applicable() {
        check_assist_not_applicable(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "<|>test";
    }
    "#,
        )
    }

    #[test]
    fn replace_string_with_char_works_inside_macros() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    format!(<|>"x", 92)
                }
                "#,
            r##"
                fn f() {
                    format!('x', 92)
                }
                "##,
        )
    }

    #[test]
    fn replace_string_with_char_works_func_args() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    find(<|>"x");
                }
                "#,
            r##"
                fn f() {
                    find('x');
                }
                "##,
        )
    }
}
<commit_msg>Update crates/assists/src/handlers/replace_string_with_char.rs<commit_after>use syntax::{
    ast::{self, HasStringValue},
    AstToken,
    SyntaxKind::STRING,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: replace_string_with_char
//
// Replace string with char.
//
// ```
// fn main() {
//     find("{<|>");
// }
// ```
// ->
// ```
// fn main() {
//     find('{');
// }
// ```
pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
    let value = token.value()?;
    let target = token.syntax().text_range();

    if value.chars().take(2).count() != 1 {
        return None;
    }

    acc.add(
        AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
        "Replace string with char",
        target,
        |edit| {
            edit.replace(token.syntax().text_range(), format!("'{}'", value));
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn replace_string_with_char_target() {
        check_assist_target(
            replace_string_with_char,
            r#"
            fn f() {
                let s = "<|>c";
            }
            "#,
            r#""c""#,
        );
    }

    #[test]
    fn replace_string_with_char_assist() {
        check_assist(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "<|>c";
    }
    "#,
            r##"
    fn f() {
        let s = 'c';
    }
    "##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_with_emoji() {
        check_assist(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "<|>😀";
    }
    "#,
            r##"
    fn f() {
        let s = '😀';
    }
    "##,
        )
    }

    #[test]
    fn replace_string_with_char_assist_not_applicable() {
        check_assist_not_applicable(
            replace_string_with_char,
            r#"
    fn f() {
        let s = "<|>test";
    }
    "#,
        )
    }

    #[test]
    fn replace_string_with_char_works_inside_macros() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    format!(<|>"x", 92)
                }
                "#,
            r##"
                fn f() {
                    format!('x', 92)
                }
                "##,
        )
    }

    #[test]
    fn replace_string_with_char_works_func_args() {
        check_assist(
            replace_string_with_char,
            r#"
                fn f() {
                    find(<|>"x");
                }
                "#,
            r##"
                fn f() {
                    find('x');
                }
                "##,
        )
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use proc_macro2::TokenStream;
use syn::{Pat, Type, TypePtr};

use crate::{
    conversion::analysis::fun::function_wrapper::{RustConversionType, TypeConversionPolicy},
    types::make_ident,
};
use quote::quote;
use syn::parse_quote;

use super::MaybeUnsafeStmt;

/// Output Rust snippets for how to deal with a given parameter.
pub(super) enum RustParamConversion {
    Param {
        ty: Type,
        local_variables: Vec<MaybeUnsafeStmt>,
        conversion: TokenStream,
        conversion_requires_unsafe: bool,
    },
    ReturnValue {
        ty: Type,
    },
}

impl TypeConversionPolicy {
    /// If returns `None` then this parameter should be omitted entirely.
    pub(super) fn rust_conversion(&self, var: Pat) -> RustParamConversion {
        match self.rust_conversion {
            RustConversionType::None => RustParamConversion::Param {
                ty: self.converted_rust_type(),
                local_variables: Vec::new(),
                conversion: quote! { #var },
                conversion_requires_unsafe: false,
            },
            RustConversionType::FromStr => RustParamConversion::Param {
                ty: parse_quote! { impl ToCppString },
                local_variables: Vec::new(),
                conversion: quote! ( #var .into_cpp() ),
                conversion_requires_unsafe: false,
            },
            RustConversionType::ToBoxedUpHolder(ref sub) => {
                let holder_type = sub.holder();
                let id = sub.id();
                let ty = parse_quote! { autocxx::subclass::CppSubclassRustPeerHolder<
                    super::super::super:: #id>
                };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        Box::new(#holder_type(#var))
                    },
                    conversion_requires_unsafe: false,
                }
            }
            RustConversionType::FromPinMaybeUninitToPtr => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => &*elem,
                    _ => panic!("Not a ptr"),
                };
                let ty = parse_quote! {
                    ::std::pin::Pin<&mut ::std::mem::MaybeUninit< #ty >>
                };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        #var.get_unchecked_mut().as_mut_ptr()
                    },
                    conversion_requires_unsafe: true,
                }
            }
            RustConversionType::FromPinMoveRefToPtr => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => &*elem,
                    _ => panic!("Not a ptr"),
                };
                let ty = parse_quote! {
                    ::std::pin::Pin<autocxx::moveit::MoveRef< '_, #ty >>
                };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        { let r: &mut _ = ::std::pin::Pin::into_inner_unchecked(#var.as_mut());
                            r
                        }
                    },
                    conversion_requires_unsafe: true,
                }
            }
            RustConversionType::FromTypeToPtr => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => &*elem,
                    _ => panic!("Not a ptr"),
                };
                let ty = parse_quote! { &mut #ty };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        #var
                    },
                    conversion_requires_unsafe: false,
                }
            }
            RustConversionType::FromValueParamToPtr | RustConversionType::FromRValueParamToPtr => {
                let (handler_type, param_trait) = match self.rust_conversion {
                    RustConversionType::FromValueParamToPtr => ("ValueParamHandler", "ValueParam"),
                    RustConversionType::FromRValueParamToPtr => {
                        ("RValueParamHandler", "RValueParam")
                    }
                    _ => unreachable!(),
                };
                let handler_type = make_ident(handler_type);
                let param_trait = make_ident(param_trait);
                let var_name = if let Pat::Ident(pti) = &var {
                    &pti.ident
                } else {
                    panic!("Unexpected non-ident parameter name");
                };
                let space_var_name = make_ident(format!("{}_space", var_name));
                let ty = &self.unwrapped_type;
                let ty = parse_quote! { impl autocxx::#param_trait<#ty> };
                // This is the usual trick to put something on the stack, then
                // immediately shadow the variable name so it can't be accessed or moved.
                RustParamConversion::Param {
                    ty,
                    local_variables: vec![
                        MaybeUnsafeStmt::new(
                            quote! { let mut #space_var_name = autocxx::#handler_type::default(); },
                        ),
                        MaybeUnsafeStmt::binary(
                            quote! { let mut #space_var_name =
                                unsafe { std::pin::Pin::new_unchecked(&mut #space_var_name) };
                            },
                            quote! { let mut #space_var_name =
                                std::pin::Pin::new_unchecked(&mut #space_var_name);
                            },
                        ),
                        MaybeUnsafeStmt::needs_unsafe(
                            quote! { #space_var_name.as_mut().populate(#var_name); },
                        ),
                    ],
                    conversion: quote! {
                        #space_var_name.get_ptr()
                    },
                    conversion_requires_unsafe: false,
                }
            }
            // This type of conversion means that this function parameter appears in the cxx::bridge
            // but not in the arguments for the wrapper function, because instead we return an
            // impl New which uses the cxx::bridge function's pointer parameter.
            RustConversionType::FromPlacementParamToNewReturn => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => *(*elem).clone(),
                    _ => panic!("Not a ptr"),
                };
                RustParamConversion::ReturnValue { ty }
            }
        }
    }
}
<commit_msg>Fix pin problem.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use proc_macro2::TokenStream;
use syn::{Pat, Type, TypePtr};

use crate::{
    conversion::analysis::fun::function_wrapper::{RustConversionType, TypeConversionPolicy},
    types::make_ident,
};
use quote::quote;
use syn::parse_quote;

use super::MaybeUnsafeStmt;

/// Output Rust snippets for how to deal with a given parameter.
pub(super) enum RustParamConversion {
    Param {
        ty: Type,
        local_variables: Vec<MaybeUnsafeStmt>,
        conversion: TokenStream,
        conversion_requires_unsafe: bool,
    },
    ReturnValue {
        ty: Type,
    },
}

impl TypeConversionPolicy {
    /// If returns `None` then this parameter should be omitted entirely.
    pub(super) fn rust_conversion(&self, var: Pat) -> RustParamConversion {
        match self.rust_conversion {
            RustConversionType::None => RustParamConversion::Param {
                ty: self.converted_rust_type(),
                local_variables: Vec::new(),
                conversion: quote! { #var },
                conversion_requires_unsafe: false,
            },
            RustConversionType::FromStr => RustParamConversion::Param {
                ty: parse_quote! { impl ToCppString },
                local_variables: Vec::new(),
                conversion: quote! ( #var .into_cpp() ),
                conversion_requires_unsafe: false,
            },
            RustConversionType::ToBoxedUpHolder(ref sub) => {
                let holder_type = sub.holder();
                let id = sub.id();
                let ty = parse_quote! { autocxx::subclass::CppSubclassRustPeerHolder<
                    super::super::super:: #id>
                };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        Box::new(#holder_type(#var))
                    },
                    conversion_requires_unsafe: false,
                }
            }
            RustConversionType::FromPinMaybeUninitToPtr => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => &*elem,
                    _ => panic!("Not a ptr"),
                };
                let ty = parse_quote! {
                    ::std::pin::Pin<&mut ::std::mem::MaybeUninit< #ty >>
                };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        #var.get_unchecked_mut().as_mut_ptr()
                    },
                    conversion_requires_unsafe: true,
                }
            }
            RustConversionType::FromPinMoveRefToPtr => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => &*elem,
                    _ => panic!("Not a ptr"),
                };
                let ty = parse_quote! {
                    ::std::pin::Pin<autocxx::moveit::MoveRef< '_, #ty >>
                };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        { let r: &mut _ = ::std::pin::Pin::into_inner_unchecked(#var.as_mut());
                            r
                        }
                    },
                    conversion_requires_unsafe: true,
                }
            }
            RustConversionType::FromTypeToPtr => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => &*elem,
                    _ => panic!("Not a ptr"),
                };
                let ty = parse_quote! { &mut #ty };
                RustParamConversion::Param {
                    ty,
                    local_variables: Vec::new(),
                    conversion: quote! {
                        #var
                    },
                    conversion_requires_unsafe: false,
                }
            }
            RustConversionType::FromValueParamToPtr | RustConversionType::FromRValueParamToPtr => {
                let (handler_type, param_trait) = match self.rust_conversion {
                    RustConversionType::FromValueParamToPtr => ("ValueParamHandler", "ValueParam"),
                    RustConversionType::FromRValueParamToPtr => {
                        ("RValueParamHandler", "RValueParam")
                    }
                    _ => unreachable!(),
                };
                let handler_type = make_ident(handler_type);
                let param_trait = make_ident(param_trait);
                let var_name = if let Pat::Ident(pti) = &var {
                    &pti.ident
                } else {
                    panic!("Unexpected non-ident parameter name");
                };
                let space_var_name = make_ident(format!("{}_space", var_name));
                let ty = &self.unwrapped_type;
                let ty = parse_quote! { impl autocxx::#param_trait<#ty> };
                // This is the usual trick to put something on the stack, then
                // immediately shadow the variable name so it can't be accessed or moved.
                RustParamConversion::Param {
                    ty,
                    local_variables: vec![
                        MaybeUnsafeStmt::new(
                            quote! { let mut #space_var_name = autocxx::#handler_type::default(); },
                        ),
                        MaybeUnsafeStmt::binary(
                            quote! { let mut #space_var_name =
                                unsafe { ::std::pin::Pin::new_unchecked(&mut #space_var_name) };
                            },
                            quote! { let mut #space_var_name =
                                ::std::pin::Pin::new_unchecked(&mut #space_var_name);
                            },
                        ),
                        MaybeUnsafeStmt::needs_unsafe(
                            quote! { #space_var_name.as_mut().populate(#var_name); },
                        ),
                    ],
                    conversion: quote! {
                        #space_var_name.get_ptr()
                    },
                    conversion_requires_unsafe: false,
                }
            }
            // This type of conversion means that this function parameter appears in the cxx::bridge
            // but not in the arguments for the wrapper function, because instead we return an
            // impl New which uses the cxx::bridge function's pointer parameter.
            RustConversionType::FromPlacementParamToNewReturn => {
                let ty = match &self.unwrapped_type {
                    Type::Ptr(TypePtr { elem, .. }) => *(*elem).clone(),
                    _ => panic!("Not a ptr"),
                };
                RustParamConversion::ReturnValue { ty }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::fmt::Debug;
use graph_neighbor_matching::{SimilarityMatrix, ScoreNorm, WeightedNodeColors, NodeColorWeight};
use graph_neighbor_matching::graph::OwnedGraph;
use graph_neighbor_matching::{Graph, Edges};
use neat::genomes::acyclic_network::NodeType;
use graph_io_gml::parse_gml;
use asexp::Sexp;
use petgraph::Directed;
use petgraph::Graph as PetGraph;
use std::f32::{INFINITY, NEG_INFINITY};
use closed01::Closed01;
use std::io::{self, Write};

fn convert_weight(w: Option<&Sexp>) -> Option<f32> {
    match w {
        Some(s) => s.get_float().map(|f| f as f32),
        None => {
            // use a default
            Some(0.0)
        }
    }
}

fn determine_edge_value_range<T>(g: &PetGraph<T, f32, Directed>) -> (f32, f32) {
    let mut w_min = INFINITY;
    let mut w_max = NEG_INFINITY;
    for i in g.raw_edges() {
        w_min = w_min.min(i.weight);
        w_max = w_max.max(i.weight);
    }
    (w_min, w_max)
}

fn normalize_to_closed01(w: f32, range: (f32, f32)) -> Closed01<f32> {
    assert!(range.1 >= range.0);
    let dist = range.1 - range.0;
    if dist == 0.0 {
        Closed01::zero()
    } else {
        Closed01::new((w - range.0) / dist)
    }
}

pub fn load_graph<N, F>(graph_file: &str, convert_node_from_str: F) -> OwnedGraph<N>
    where N: Clone + Debug,
          F: Fn(&str) -> N
{
    info!("Loading graph file: {}", graph_file);

    let graph_s = {
        let mut graph_file = File::open(graph_file).unwrap();
        let mut graph_s = String::new();
        let _ = graph_file.read_to_string(&mut graph_s).unwrap();
        graph_s
    };

    let graph = parse_gml(&graph_s,
                          &|node_sexp| -> Option<N> {
                              node_sexp.and_then(|se| se.get_str().map(|s| convert_node_from_str(s)))
                          },
                          &convert_weight)
                    .unwrap();
    let edge_range = determine_edge_value_range(&graph);
    let graph = graph.map(|_, nw| nw.clone(),
                          |_, &ew| normalize_to_closed01(ew, edge_range));

    OwnedGraph::from_petgraph(&graph)
}

pub fn write_gml(filename: &str, graph: &OwnedGraph<Neuron>) {
    let mut file = File::create(filename).unwrap();
    to_gml(&mut file, graph).unwrap();
}

pub fn to_gml<W: Write>(wr: &mut W, graph: &OwnedGraph<Neuron>) -> io::Result<()> {
    try!(writeln!(wr, "graph ["));
    try!(writeln!(wr, "  directed 1"));

    for nidx in 0..graph.num_nodes() {
        let node_type: f32 = graph.node_value(nidx).node_color_weight();
        try!(writeln!(wr, "  node [id {} weight {:.1}]", nidx, node_type));
    }
    for nidx in 0..graph.num_nodes() {
        let edges = graph.out_edges_of(nidx);
        for eidx in 0..edges.num_edges() {
            try!(writeln!(wr, "  edge [source {} target {} weight {:.2}]", nidx, edges.nth_edge(eidx).unwrap(), edges.nth_edge_weight(eidx).unwrap().get()));
        }
    }
    try!(writeln!(wr, "]"));
    Ok(())
}

#[derive(Debug)]
pub struct NodeCount {
    pub inputs: usize,
    pub outputs: usize,
    pub hidden: usize,
}

impl NodeCount {
    pub fn from_graph(graph: &OwnedGraph<Neuron>) -> Self {
        let mut cnt = NodeCount {
            inputs: 0,
            outputs: 0,
            hidden: 0
        };

        for node in graph.nodes() {
            match node.node_value() {
                &Neuron::Input => {
                    cnt.inputs += 1;
                }
                &Neuron::Output => {
                    cnt.outputs += 1;
                }
                &Neuron::Hidden => {
                    cnt.hidden += 1;
                }
            }
        }

        return cnt;
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Neuron {
    Input,
    Output,
    Hidden,
}

impl NodeColorWeight for Neuron {
    fn node_color_weight(&self) -> f32 {
        match *self {
            Neuron::Input => 0.0,
            Neuron::Hidden => 1.0,
            Neuron::Output => 2.0,
        }
    }
}

impl NodeType for Neuron {
    fn accept_incoming_links(&self) -> bool {
        match *self {
            Neuron::Input => false,
            _ => true,
        }
    }
    fn accept_outgoing_links(&self) -> bool {
        match *self {
            Neuron::Output => false,
            _ => true,
        }
    }
}

pub fn convert_neuron_from_str(s: &str) -> Neuron {
    match s {
        "input" => Neuron::Input,
        "output" => Neuron::Output,
        "hidden" => Neuron::Hidden,
        _ => panic!("Invalid node type/weight"),
    }
}

#[derive(Debug)]
pub struct GraphSimilarity {
    pub target_graph: OwnedGraph<Neuron>,
    pub edge_score: bool,
    pub iters: usize,
    pub eps: f32,
}

impl GraphSimilarity {
    // A larger fitness means "better"
    pub fn fitness(&self, graph: &OwnedGraph<Neuron>) -> f32 {
        let mut s = SimilarityMatrix::new(graph, &self.target_graph, WeightedNodeColors);
        s.iterate(self.iters, self.eps);
        let assignment = s.optimal_node_assignment();
        if self.edge_score {
            s.score_outgoing_edge_weights_sum_norm(&assignment, ScoreNorm::MaxDegree).get()
        } else {
            s.score_optimal_sum_norm(Some(&assignment), ScoreNorm::MaxDegree).get()
        }
    }
}
<commit_msg>In case of edge weight scoring, multiply the edge score with the node neighbor matching score.<commit_after>use std::fs::File;
use std::io::Read;
use std::fmt::Debug;
use graph_neighbor_matching::{SimilarityMatrix, ScoreNorm, WeightedNodeColors, NodeColorWeight};
use graph_neighbor_matching::graph::OwnedGraph;
use graph_neighbor_matching::{Graph, Edges};
use neat::genomes::acyclic_network::NodeType;
use graph_io_gml::parse_gml;
use asexp::Sexp;
use petgraph::Directed;
use petgraph::Graph as PetGraph;
use std::f32::{INFINITY, NEG_INFINITY};
use closed01::Closed01;
use std::io::{self, Write};

fn convert_weight(w: Option<&Sexp>) -> Option<f32> {
    match w {
        Some(s) => s.get_float().map(|f| f as f32),
        None => {
            // use a default
            Some(0.0)
        }
    }
}

fn determine_edge_value_range<T>(g: &PetGraph<T, f32, Directed>) -> (f32, f32) {
    let mut w_min = INFINITY;
    let mut w_max = NEG_INFINITY;
    for i in g.raw_edges() {
        w_min = w_min.min(i.weight);
        w_max = w_max.max(i.weight);
    }
    (w_min, w_max)
}

fn normalize_to_closed01(w: f32, range: (f32, f32)) -> Closed01<f32> {
    assert!(range.1 >= range.0);
    let dist = range.1 - range.0;
    if dist == 0.0 {
        Closed01::zero()
    } else {
        Closed01::new((w - range.0) / dist)
    }
}

pub fn load_graph<N, F>(graph_file: &str, convert_node_from_str: F) -> OwnedGraph<N>
    where N: Clone + Debug,
          F: Fn(&str) -> N
{
    info!("Loading graph file: {}", graph_file);

    let graph_s = {
        let mut graph_file = File::open(graph_file).unwrap();
        let mut graph_s = String::new();
        let _ = graph_file.read_to_string(&mut graph_s).unwrap();
        graph_s
    };

    let graph = parse_gml(&graph_s,
                          &|node_sexp| -> Option<N> {
                              node_sexp.and_then(|se| se.get_str().map(|s| convert_node_from_str(s)))
                          },
                          &convert_weight)
                    .unwrap();
    let edge_range = determine_edge_value_range(&graph);
    let graph = graph.map(|_, nw| nw.clone(),
                          |_, &ew| normalize_to_closed01(ew, edge_range));

    OwnedGraph::from_petgraph(&graph)
}

pub fn write_gml(filename: &str, graph: &OwnedGraph<Neuron>) {
    let mut file = File::create(filename).unwrap();
    to_gml(&mut file, graph).unwrap();
}

pub fn to_gml<W: Write>(wr: &mut W, graph: &OwnedGraph<Neuron>) -> io::Result<()> {
    try!(writeln!(wr, "graph ["));
    try!(writeln!(wr, "  directed 1"));

    for nidx in 0..graph.num_nodes() {
        let node_type: f32 = graph.node_value(nidx).node_color_weight();
        try!(writeln!(wr, "  node [id {} weight {:.1}]", nidx, node_type));
    }
    for nidx in 0..graph.num_nodes() {
        let edges = graph.out_edges_of(nidx);
        for eidx in 0..edges.num_edges() {
            try!(writeln!(wr, "  edge [source {} target {} weight {:.2}]", nidx, edges.nth_edge(eidx).unwrap(), edges.nth_edge_weight(eidx).unwrap().get()));
        }
    }
    try!(writeln!(wr, "]"));
    Ok(())
}

#[derive(Debug)]
pub struct NodeCount {
    pub inputs: usize,
    pub outputs: usize,
    pub hidden: usize,
}

impl NodeCount {
    pub fn from_graph(graph: &OwnedGraph<Neuron>) -> Self {
        let mut cnt = NodeCount {
            inputs: 0,
            outputs: 0,
            hidden: 0
        };

        for node in graph.nodes() {
            match node.node_value() {
                &Neuron::Input => {
                    cnt.inputs += 1;
                }
                &Neuron::Output => {
                    cnt.outputs += 1;
                }
                &Neuron::Hidden => {
                    cnt.hidden += 1;
                }
            }
        }

        return cnt;
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Neuron {
    Input,
    Output,
    Hidden,
}

impl NodeColorWeight for Neuron {
    fn node_color_weight(&self) -> f32 {
        match *self {
            Neuron::Input => 0.0,
            Neuron::Hidden => 1.0,
            Neuron::Output => 2.0,
        }
    }
}

impl NodeType for Neuron {
    fn accept_incoming_links(&self) -> bool {
        match *self {
            Neuron::Input => false,
            _ => true,
        }
    }
    fn accept_outgoing_links(&self) -> bool {
        match *self {
            Neuron::Output => false,
            _ => true,
        }
    }
}

pub fn convert_neuron_from_str(s: &str) -> Neuron {
    match s {
        "input" => Neuron::Input,
        "output" => Neuron::Output,
        "hidden" => Neuron::Hidden,
        _ => panic!("Invalid node type/weight"),
    }
}

#[derive(Debug)]
pub struct GraphSimilarity {
    pub target_graph: OwnedGraph<Neuron>,
    pub edge_score: bool,
    pub iters: usize,
    pub eps: f32,
}

impl GraphSimilarity {
    // A larger fitness means "better"
    pub fn fitness(&self, graph: &OwnedGraph<Neuron>) -> f32 {
        let mut s = SimilarityMatrix::new(graph, &self.target_graph, WeightedNodeColors);
        s.iterate(self.iters, self.eps);
        let assignment = s.optimal_node_assignment();
        let score = s.score_optimal_sum_norm(Some(&assignment), ScoreNorm::MaxDegree).get();
        if self.edge_score {
            score * s.score_outgoing_edge_weights_sum_norm(&assignment, ScoreNorm::MaxDegree).get()
        } else {
            score
        }
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crypto::{PubKey, Sign, Signature, SIGNATURE_BYTES_LEN};
use libproto::*;
use libproto::blockchain::*;
use protobuf::Message;
use std::collections::{HashMap, HashSet};
use std::result::Result;
use std::sync::mpsc::Sender;
use util::{H256, BLOCKLIMIT};

#[derive(Debug, Clone)]
pub struct Verifier {
    inited: bool,
    height_latest: Option<u64>,
    height_low: Option<u64>,
    hashes: HashMap<u64, HashSet<H256>>,
}

impl Default for Verifier {
    fn default() -> Verifier {
        Verifier {
            inited: false,
            height_latest: None,
            height_low: None,
            hashes: HashMap::with_capacity(BLOCKLIMIT as usize),
        }
    }
}

impl Verifier {
    pub fn new() -> Self {
        Verifier::default()
    }

    pub fn is_inited(&self) -> bool {
        self.inited
    }

    pub fn get_height_latest(&self) -> Option<u64> {
        self.height_latest
    }

    pub fn get_height_low(&self) -> Option<u64> {
        self.height_low
    }

    pub fn update_hashes(&mut self, h: u64, hashes: HashSet<H256>, tx_pub: &Sender<(String, Vec<u8>)>) {
        if self.height_latest.is_none() && self.height_low.is_none() {
            self.height_latest = Some(h);
            self.height_low = if h < BLOCKLIMIT {
                Some(0)
            } else {
                Some(h - BLOCKLIMIT + 1)
            };
            for i in self.height_low.unwrap()..h {
                let mut req = BlockTxHashesReq::new();
                req.set_height(i as u64);
                let msg = factory::create_msg(
                    submodules::AUTH,
                    topics::BLOCK_TXHASHES_REQ,
                    communication::MsgType::BLOCK_TXHASHES_REQ,
                    req.write_to_bytes().unwrap(),
                );
                tx_pub
                    .send((
                        "auth.blk_tx_hashs_req".to_string(),
                        msg.write_to_bytes().unwrap(),
                    ))
                    .unwrap();
            }
        } else {
            let current_height = self.height_latest.unwrap();
            let current_height_low = self.height_low.unwrap();
            if h > current_height {
                self.height_latest = Some(h);
                self.height_low = if h < BLOCKLIMIT {
                    Some(0)
                } else {
                    Some(h - BLOCKLIMIT + 1)
                };
                for i in current_height_low..self.height_low.unwrap() {
                    self.hashes.remove(&i);
                }
            }
            if h < self.height_low.unwrap() {
                return;
            }
        }
        trace!(
            "update block's tx hashes for height:{} and the current low height:{} and latest height:{}",
            h,
            self.height_low.unwrap(),
            self.height_latest.unwrap()
        );
        self.hashes.insert(h, hashes);
        if self.hashes.len() as u64 == (self.height_latest.unwrap() - self.height_low.unwrap() + 1) {
            self.inited = true;
        }
    }

    pub fn check_hash_exist(&self, hash: &H256) -> bool {
        if !self.inited {
            return true;
        }
        for (height, hashes) in &self.hashes {
            if hashes.contains(hash) {
                trace!(
                    "Tx with hash {:?} has already existed in height:{}",
                    hash.0,
                    height
                );
                return true;
            }
        }
        false
    }

    pub fn verify_sig(&self, req: &VerifyTxReq) -> Result<PubKey, ()> {
        let hash = H256::from(req.get_hash());
        let sig_bytes = req.get_signature();
        if sig_bytes.len() != SIGNATURE_BYTES_LEN {
            warn!("Unvalid signature bytes");
            return Err(());
        }
        let sig = Signature::from(sig_bytes);
        match req.get_crypto() {
            Crypto::SECP => sig.recover(&hash).map_err(|_| ()),
            _ => {
                warn!("Unexpected crypto");
                Err(())
            }
        }
    }

    pub fn verify_valid_until_block(&self, valid_until_block: u64) -> bool {
        let mut result = false;
        if let Some(height) = self.height_latest {
            result = valid_until_block > height && valid_until_block <= (height + BLOCKLIMIT);
            if result {
                warn!(
                    "The new tx is out of time valid_until_block: {:?}, height: {:?}, BLOCKLIMIT: {:?}",
                    valid_until_block,
                    height,
                    BLOCKLIMIT
                );
            }
        }
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::channel;

    #[test]
    fn verify_init() {
        let mut v = Verifier::new();
        assert_eq!(v.is_inited(), false);
        let (tx_pub, _) = channel();
        v.update_hashes(0, HashSet::new(), &tx_pub);
        assert_eq!(v.is_inited(), true);
        assert_eq!(v.get_height_latest(), Some(0));
        assert_eq!(v.get_height_low(), Some(0));
    }

    #[test]
    fn verify_update() {
        let mut v = Verifier::new();
        let (tx_pub, _rx_pub) = channel();
        v.update_hashes(100, HashSet::new(), &tx_pub);
        assert_eq!(v.is_inited(), false);
        assert_eq!(v.get_height_latest(), Some(100));
        assert_eq!(v.get_height_low(), Some(1));
        for i in 0..99 {
            v.update_hashes(i, HashSet::new(), &tx_pub);
        }
        assert_eq!(v.is_inited(), false);
        v.update_hashes(99, HashSet::new(), &tx_pub);
        assert_eq!(v.is_inited(), true);

        v.update_hashes(101, HashSet::new(), &tx_pub);
        assert_eq!(v.get_height_latest(), Some(101));
        assert_eq!(v.get_height_low(), Some(2));
    }
}
<commit_msg>[chore]fix warn<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crypto::{PubKey, Sign, Signature, SIGNATURE_BYTES_LEN};
use libproto::*;
use libproto::blockchain::*;
use protobuf::Message;
use std::collections::{HashMap, HashSet};
use std::result::Result;
use std::sync::mpsc::Sender;
use util::{H256, BLOCKLIMIT};

#[derive(Debug, Clone)]
pub struct Verifier {
    inited: bool,
    height_latest: Option<u64>,
    height_low: Option<u64>,
    hashes: HashMap<u64, HashSet<H256>>,
}

impl Default for Verifier {
    fn default() -> Verifier {
        Verifier {
            inited: false,
            height_latest: None,
            height_low: None,
            hashes: HashMap::with_capacity(BLOCKLIMIT as usize),
        }
    }
}

impl Verifier {
    pub fn new() -> Self {
        Verifier::default()
    }

    pub fn is_inited(&self) -> bool {
        self.inited
    }

    pub fn get_height_latest(&self) -> Option<u64> {
        self.height_latest
    }

    pub fn get_height_low(&self) -> Option<u64> {
        self.height_low
    }

    pub fn update_hashes(&mut self, h: u64, hashes: HashSet<H256>, tx_pub: &Sender<(String, Vec<u8>)>) {
        if self.height_latest.is_none() && self.height_low.is_none() {
            self.height_latest = Some(h);
            self.height_low = if h < BLOCKLIMIT {
                Some(0)
            } else {
                Some(h - BLOCKLIMIT + 1)
            };
            for i in self.height_low.unwrap()..h {
                let mut req = BlockTxHashesReq::new();
                req.set_height(i as u64);
                let msg = factory::create_msg(
                    submodules::AUTH,
                    topics::BLOCK_TXHASHES_REQ,
                    communication::MsgType::BLOCK_TXHASHES_REQ,
                    req.write_to_bytes().unwrap(),
                );
                tx_pub
                    .send((
                        "auth.blk_tx_hashs_req".to_string(),
                        msg.write_to_bytes().unwrap(),
                    ))
                    .unwrap();
            }
        } else {
            let current_height = self.height_latest.unwrap();
            let current_height_low = self.height_low.unwrap();
            if h > current_height {
                self.height_latest = Some(h);
                self.height_low = if h < BLOCKLIMIT {
                    Some(0)
                } else {
                    Some(h - BLOCKLIMIT + 1)
                };
                for i in current_height_low..self.height_low.unwrap() {
                    self.hashes.remove(&i);
                }
            }
            if h < self.height_low.unwrap() {
                return;
            }
        }
        trace!(
            "update block's tx hashes for height:{} and the current low height:{} and latest height:{}",
            h,
            self.height_low.unwrap(),
            self.height_latest.unwrap()
        );
        self.hashes.insert(h, hashes);
        if self.hashes.len() as u64 == (self.height_latest.unwrap() - self.height_low.unwrap() + 1) {
            self.inited = true;
        }
    }

    pub fn check_hash_exist(&self, hash: &H256) -> bool {
        if !self.inited {
            return true;
        }
        for (height, hashes) in &self.hashes {
            if hashes.contains(hash) {
                trace!(
                    "Tx with hash {:?} has already existed in height:{}",
                    hash.0,
                    height
                );
                return true;
            }
        }
        false
    }

    pub fn verify_sig(&self, req: &VerifyTxReq) -> Result<PubKey, ()> {
        let hash = H256::from(req.get_hash());
        let sig_bytes = req.get_signature();
        if sig_bytes.len() != SIGNATURE_BYTES_LEN {
            warn!("Unvalid signature bytes");
            return Err(());
        }
        let sig = Signature::from(sig_bytes);
        match req.get_crypto() {
            Crypto::SECP => sig.recover(&hash).map_err(|_| ()),
            _ => {
                warn!("Unexpected crypto");
                Err(())
            }
        }
    }

    pub fn verify_valid_until_block(&self, valid_until_block: u64) -> bool {
        let mut result = false;
        if let Some(height) = self.height_latest {
            result = valid_until_block > height && valid_until_block <= (height + BLOCKLIMIT);
            if !result {
                warn!(
                    "The new tx is out of time valid_until_block: {:?}, height: {:?}, BLOCKLIMIT: {:?}",
                    valid_until_block,
                    height,
                    BLOCKLIMIT
                );
            }
        }
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::channel;

    #[test]
    fn verify_init() {
        let mut v = Verifier::new();
        assert_eq!(v.is_inited(), false);
        let (tx_pub, _) = channel();
        v.update_hashes(0, HashSet::new(), &tx_pub);
        assert_eq!(v.is_inited(), true);
        assert_eq!(v.get_height_latest(), Some(0));
        assert_eq!(v.get_height_low(), Some(0));
    }

    #[test]
    fn verify_update() {
        let mut v = Verifier::new();
        let (tx_pub, _rx_pub) = channel();
        v.update_hashes(100, HashSet::new(), &tx_pub);
        assert_eq!(v.is_inited(), false);
        assert_eq!(v.get_height_latest(), Some(100));
        assert_eq!(v.get_height_low(), Some(1));
        for i in 0..99 {
            v.update_hashes(i, HashSet::new(), &tx_pub);
        }
        assert_eq!(v.is_inited(), false);
        v.update_hashes(99, HashSet::new(), &tx_pub);
        assert_eq!(v.is_inited(), true);

        v.update_hashes(101, HashSet::new(), &tx_pub);
        assert_eq!(v.get_height_latest(), Some(101));
        assert_eq!(v.get_height_low(), Some(2));
    }
}
<|endoftext|>


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

#![feature(alloc)]
#![no_std]

extern crate alloc;
extern crate tock;

fn main() {
	use tock::console::Console;

	let mut console = Console::new();
	loop {
		use core::fmt::Write;
		use tock::timer;
		console.write_str("Hello, World!\n").expect("Failed console write");
		timer::sleep(timer::Duration::from_ms(1000));
	}
}
<commit_msg>rustfmt main.rs<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(alloc)]
#![no_std]

extern crate alloc;
extern crate tock;

fn main() {
    use tock::console::Console;

    let mut console = Console::new();
    loop {
        use core::fmt::Write;
        use tock::timer;
        console
            .write_str("Hello, World!\n")
            .expect("Failed console write");
        timer::sleep(timer::Duration::from_ms(1000));
    }
}
<|endoftext|>