<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding;
use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding::XRRigidTransformMethods;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::dompointreadonly::DOMPointReadOnly;
use crate::dom::globalscope::GlobalScope;
use crate::dom::vrframedata::create_typed_array;
use crate::dom::window::Window;
use dom_struct::dom_struct;
use euclid::{RigidTransform3D, Rotation3D, Vector3D};
use js::jsapi::{Heap, JSContext, JSObject};
use std::ptr::NonNull;

#[dom_struct]
pub struct XRRigidTransform {
    reflector_: Reflector,
    position: MutNullableDom<DOMPointReadOnly>,
    orientation: MutNullableDom<DOMPointReadOnly>,
    #[ignore_malloc_size_of = "defined in euclid"]
    transform: RigidTransform3D<f64>,
    inverse: MutNullableDom<XRRigidTransform>,
    matrix: Heap<*mut JSObject>,
}

impl XRRigidTransform {
    fn new_inherited(transform: RigidTransform3D<f64>) -> XRRigidTransform {
        XRRigidTransform {
            reflector_: Reflector::new(),
            position: MutNullableDom::default(),
            orientation: MutNullableDom::default(),
            transform,
            inverse: MutNullableDom::default(),
            matrix: Heap::default(),
        }
    }

    pub fn new(
        global: &GlobalScope,
        transform: RigidTransform3D<f64>,
    ) -> DomRoot<XRRigidTransform> {
        reflect_dom_object(
            Box::new(XRRigidTransform::new_inherited(transform)),
            global,
            XRRigidTransformBinding::Wrap,
        )
    }

    pub fn identity(window: &GlobalScope) -> DomRoot<XRRigidTransform> {
        let transform = RigidTransform3D::identity();
        XRRigidTransform::new(window, transform)
    }

    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-xrrigidtransform
    pub fn Constructor(
        window: &Window,
        position: &DOMPointInit,
        orientation: &DOMPointInit,
    ) -> Fallible<DomRoot<Self>> {
        if position.w != 1.0 {
            return Err(Error::Type(format!(
                "XRRigidTransform must be constructed with a position that has a w value of of 1.0, not {}",
                position.w
            )));
        }

        let translate = Vector3D::new(position.x as f64, position.y as f64, position.z as f64);
        let rotate = Rotation3D::unit_quaternion(
            orientation.x as f64,
            orientation.y as f64,
            orientation.z as f64,
            orientation.w as f64,
        );
        let transform = RigidTransform3D::new(rotate, translate);
        Ok(XRRigidTransform::new(&window.global(), transform))
    }
}

impl XRRigidTransformMethods for XRRigidTransform {
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-position
    fn Position(&self) -> DomRoot<DOMPointReadOnly> {
        self.position.or_init(|| {
            let t = &self.transform.translation;
            DOMPointReadOnly::new(&self.global(), t.x, t.y, t.z, 1.0)
        })
    }
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-orientation
    fn Orientation(&self) -> DomRoot<DOMPointReadOnly> {
        self.position.or_init(|| {
            let r = &self.transform.rotation;
            DOMPointReadOnly::new(&self.global(), r.i, r.j, r.k, r.r)
        })
    }
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-inverse
    fn Inverse(&self) -> DomRoot<XRRigidTransform> {
        self.inverse
            .or_init(|| XRRigidTransform::new(&self.global(), self.transform.inverse()))
    }
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-matrix
    #[allow(unsafe_code)]
    unsafe fn Matrix(&self, _cx: *mut JSContext) -> NonNull<JSObject> {
        if self.matrix.get().is_null() {
            let cx = self.global().get_cx();
            // According to the spec all matrices are column-major,
            // however euclid uses row vectors so we use .to_row_major_array()
            let arr = self.transform.to_transform().cast().to_row_major_array();
            create_typed_array(cx, &arr, &self.matrix);
        }
        NonNull::new(self.matrix.get()).unwrap()
    }
}

impl XRRigidTransform {
    /// https://immersive-web.github.io/webxr/#dom-xrpose-transform
    pub fn transform(&self) -> RigidTransform3D<f64> {
        self.transform
    }
}
<commit_msg>Set transform.inverse.inverse == transform<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding;
use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding::XRRigidTransformMethods;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::dompointreadonly::DOMPointReadOnly;
use crate::dom::globalscope::GlobalScope;
use crate::dom::vrframedata::create_typed_array;
use crate::dom::window::Window;
use dom_struct::dom_struct;
use euclid::{RigidTransform3D, Rotation3D, Vector3D};
use js::jsapi::{Heap, JSContext, JSObject};
use std::ptr::NonNull;

#[dom_struct]
pub struct XRRigidTransform {
    reflector_: Reflector,
    position: MutNullableDom<DOMPointReadOnly>,
    orientation: MutNullableDom<DOMPointReadOnly>,
    #[ignore_malloc_size_of = "defined in euclid"]
    transform: RigidTransform3D<f64>,
    inverse: MutNullableDom<XRRigidTransform>,
    matrix: Heap<*mut JSObject>,
}

impl XRRigidTransform {
    fn new_inherited(transform: RigidTransform3D<f64>) -> XRRigidTransform {
        XRRigidTransform {
            reflector_: Reflector::new(),
            position: MutNullableDom::default(),
            orientation: MutNullableDom::default(),
            transform,
            inverse: MutNullableDom::default(),
            matrix: Heap::default(),
        }
    }

    pub fn new(
        global: &GlobalScope,
        transform: RigidTransform3D<f64>,
    ) -> DomRoot<XRRigidTransform> {
        reflect_dom_object(
            Box::new(XRRigidTransform::new_inherited(transform)),
            global,
            XRRigidTransformBinding::Wrap,
        )
    }

    pub fn identity(window: &GlobalScope) -> DomRoot<XRRigidTransform> {
        let transform = RigidTransform3D::identity();
        XRRigidTransform::new(window, transform)
    }

    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-xrrigidtransform
    pub fn Constructor(
        window: &Window,
        position: &DOMPointInit,
        orientation: &DOMPointInit,
    ) -> Fallible<DomRoot<Self>> {
        if position.w != 1.0 {
            return Err(Error::Type(format!(
                "XRRigidTransform must be constructed with a position that has a w value of of 1.0, not {}",
                position.w
            )));
        }

        let translate = Vector3D::new(position.x as f64, position.y as f64, position.z as f64);
        let rotate = Rotation3D::unit_quaternion(
            orientation.x as f64,
            orientation.y as f64,
            orientation.z as f64,
            orientation.w as f64,
        );
        let transform = RigidTransform3D::new(rotate, translate);
        Ok(XRRigidTransform::new(&window.global(), transform))
    }
}

impl XRRigidTransformMethods for XRRigidTransform {
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-position
    fn Position(&self) -> DomRoot<DOMPointReadOnly> {
        self.position.or_init(|| {
            let t = &self.transform.translation;
            DOMPointReadOnly::new(&self.global(), t.x, t.y, t.z, 1.0)
        })
    }
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-orientation
    fn Orientation(&self) -> DomRoot<DOMPointReadOnly> {
        self.position.or_init(|| {
            let r = &self.transform.rotation;
            DOMPointReadOnly::new(&self.global(), r.i, r.j, r.k, r.r)
        })
    }
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-inverse
    fn Inverse(&self) -> DomRoot<XRRigidTransform> {
        self.inverse.or_init(|| {
            let transform = XRRigidTransform::new(&self.global(), self.transform.inverse());
            transform.inverse.set(Some(self));
            transform
        })
    }
    // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-matrix
    #[allow(unsafe_code)]
    unsafe fn Matrix(&self, _cx: *mut JSContext) -> NonNull<JSObject> {
        if self.matrix.get().is_null() {
            let cx = self.global().get_cx();
            // According to the spec all matrices are column-major,
            // however euclid uses row vectors so we use .to_row_major_array()
            let arr = self.transform.to_transform().cast().to_row_major_array();
            create_typed_array(cx, &arr, &self.matrix);
        }
        NonNull::new(self.matrix.get()).unwrap()
    }
}

impl XRRigidTransform {
    /// https://immersive-web.github.io/webxr/#dom-xrpose-transform
    pub fn transform(&self) -> RigidTransform3D<f64> {
        self.transform
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    config::{Config, ConfigPath},
    error::Error,
    secure_backend::ValidatorBackend,
    transaction::build_raw_transaction,
};
use core::str::FromStr;
use diem_config::config::HANDSHAKE_VERSION;
use diem_global_constants::{
    CONSENSUS_KEY, FULLNODE_NETWORK_KEY, OPERATOR_ACCOUNT, OPERATOR_KEY, OWNER_ACCOUNT,
    VALIDATOR_NETWORK_KEY,
};
use diem_transaction_builder::stdlib as transaction_builder;
use diem_types::{
    chain_id::ChainId,
    network_address::{NetworkAddress, Protocol},
    transaction::Transaction,
};
use std::net::{Ipv4Addr, ToSocketAddrs};
use structopt::StructOpt;

#[derive(Clone, Debug, StructOpt)]
pub struct ValidatorConfig {
    #[structopt(flatten)]
    pub config: ConfigPath,
    #[structopt(long, required_unless("config"))]
    pub chain_id: Option<ChainId>,
    #[structopt(flatten)]
    pub validator_backend: ValidatorBackend,
}

impl ValidatorConfig {
    pub fn config(&self) -> Result<Config, Error> {
        self.config
            .load()?
            .override_chain_id(self.chain_id)
            .override_validator_backend(&self.validator_backend.validator_backend)
    }

    pub fn build_transaction(
        &self,
        sequence_number: u64,
        fullnode_address: NetworkAddress,
        validator_address: NetworkAddress,
        reconfigure: bool,
        disable_address_validation: bool,
    ) -> Result<Transaction, Error> {
        if !disable_address_validation {
            // Verify addresses
            validate_address("validator address", &validator_address)?;
            validate_address("fullnode address", &fullnode_address)?;
        }

        let config = self.config()?;
        let mut storage = config.validator_backend();

        let owner_account = storage.account_address(OWNER_ACCOUNT)?;

        let consensus_key = storage.ed25519_public_from_private(CONSENSUS_KEY)?;
        let fullnode_network_key = storage.x25519_public_from_private(FULLNODE_NETWORK_KEY)?;
        let validator_network_key = storage.x25519_public_from_private(VALIDATOR_NETWORK_KEY)?;

        // Build Validator address including protocols and encryption
        // Append ln-noise-ik and ln-handshake protocols to base network addresses
        // and encrypt the validator address.
        let validator_address =
            validator_address.append_prod_protos(validator_network_key, HANDSHAKE_VERSION);
        let encryptor = config.validator_backend().encryptor();
        let validator_addresses = encryptor
            .encrypt(
                &[validator_address],
                owner_account,
                sequence_number + if reconfigure { 1 } else { 0 },
            )
            .map_err(|e| {
                Error::UnexpectedError(format!("Error encrypting validator address: {}", e))
            })?;

        // Build Fullnode address including protocols
        let fullnode_address =
            fullnode_address.append_prod_protos(fullnode_network_key, HANDSHAKE_VERSION);

        // Generate the validator config script
        let transaction_callback = if reconfigure {
            transaction_builder::encode_set_validator_config_and_reconfigure_script_function
        } else {
            transaction_builder::encode_register_validator_config_script_function
        };
        let validator_config_script = transaction_callback(
            owner_account,
            consensus_key.to_bytes().to_vec(),
            validator_addresses,
            bcs::to_bytes(&vec![fullnode_address]).unwrap(),
        )
        .into_script_function();

        // Create and sign the validator-config transaction
        let raw_txn = build_raw_transaction(
            config.chain_id,
            storage.account_address(OPERATOR_ACCOUNT)?,
            sequence_number,
            validator_config_script,
        );
        let signed_txn = storage.sign(OPERATOR_KEY, "validator-config", raw_txn)?;
        let txn = Transaction::UserTransaction(signed_txn);

        Ok(txn)
    }
}

/// Validates an address to have a DNS/IP and a port, as well as to be resolvable
pub fn validate_address(
    address_name: &'static str,
    network_address: &NetworkAddress,
) -> Result<(), Error> {
    let mut has_addr = false;
    let mut has_port = false;
    // Only allow DNS and IP addresses
    for protocol in network_address.as_slice().iter() {
        match protocol {
            Protocol::Ip4(_) => has_addr = true,
            Protocol::Dns4(dns_name) => {
                let dns_name = format!("{}", dns_name);
                if Ipv4Addr::from_str(&dns_name).is_ok() {
                    return Err(Error::CommandArgumentError(format!(
                        "{}: Please use the /ip4/ protocol for IP addresses",
                        address_name
                    )));
                }
                has_addr = true
            }
            Protocol::Tcp(_) => has_port = true,
            Protocol::Dns(_) | Protocol::Ip6(_) | Protocol::Dns6(_) => {
                return Err(Error::CommandArgumentError(format!(
                    "{}: IPv6 is currently not supported.  Protocol: '{}'",
                    address_name, protocol
                )))
            }
            _ => {
                return Err(Error::CommandArgumentError(format!(
                    "{}: Invalid protocol '{}'",
                    address_name, protocol
                )))
            }
        }
    }

    if !has_addr || !has_port {
        return Err(Error::CommandArgumentError(format!(
            "{}: Address must have a scheme (e.g. /ipv4/) and a port (e.g. /tcp/)",
            address_name
        )));
    }

    // Ensure that the address resolves to IP addresses
    let addrs = network_address.to_socket_addrs().map_err(|err| {
        Error::CommandArgumentError(format!(
            "{}: Failed to resolve address '{}': {}",
            address_name, network_address, err
        ))
    })?;

    if addrs.len() < 1 {
        return Err(Error::CommandArgumentError(format!(
            "{}: Resolved to no IP addresses '{}'",
            address_name, network_address
        )));
    }

    Ok(())
}

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

    #[test]
    fn test_invalid_inputs() {
        let no_port = NetworkAddress::from_str("/ip4/127.0.0.1").unwrap();
        let no_ip = NetworkAddress::from_str("/tcp/1234").unwrap();
        let ipv6 = NetworkAddress::from_str("/dns6/localhost").unwrap();
        let ipv4_and_ipv6 = NetworkAddress::from_str("/dns/localhost").unwrap();
        let bad_protocol = NetworkAddress::from_str("/ln-handshake/0").unwrap();
        let ip_in_dns = NetworkAddress::from_str("/dns4/127.0.0.1/tcp/1234").unwrap();

        validate_address("no_port", &no_port).expect_err("Failed to check for port");
        validate_address("no_ip", &no_ip).expect_err("Failed to check for no IP");
        validate_address("ipv6", &ipv6).expect_err("Failed to check for ipv6");
        validate_address("ipv4_and_ipv6", &ipv4_and_ipv6).expect_err("Failed to check for ipv6");
        validate_address("bad_protocol", &bad_protocol)
            .expect_err("Failed to check for bad protocol");
        validate_address("ip_in_dns", &ip_in_dns).expect_err("Failed to check for ip in DNS");
    }

    #[test]
    fn test_valid_inputs() {
        let ip = NetworkAddress::from_str("/ip4/127.0.0.1/tcp/1234").unwrap();
        let dns = NetworkAddress::from_str("/dns4/localhost/tcp/1234").unwrap();

        validate_address("ip", &ip).expect("IP failed to validate");
        validate_address("dns", &dns).expect("DNS failed to validate");
    }
}
<commit_msg>management: enable creation of a ValidatorConfig from any S: KVStorage + CryptoStorage<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    config::{Config, ConfigPath},
    error::Error,
    secure_backend::ValidatorBackend,
    storage::to_x25519,
    transaction::build_raw_transaction,
};
use core::str::FromStr;
use diem_config::config::HANDSHAKE_VERSION;
use diem_global_constants::{
    CONSENSUS_KEY, FULLNODE_NETWORK_KEY, OPERATOR_ACCOUNT, OPERATOR_KEY, OWNER_ACCOUNT,
    VALIDATOR_NETWORK_KEY,
};
use diem_network_address_encryption::Encryptor;
use diem_secure_storage::{CryptoStorage, KVStorage, Storage};
use diem_transaction_builder::stdlib as transaction_builder;
use diem_types::{
    account_address::AccountAddress,
    chain_id::ChainId,
    network_address::{NetworkAddress, Protocol},
    transaction::{SignedTransaction, Transaction},
};
use std::net::{Ipv4Addr, ToSocketAddrs};
use structopt::StructOpt;

#[derive(Clone, Debug, StructOpt)]
pub struct ValidatorConfig {
    #[structopt(flatten)]
    pub config: ConfigPath,
    #[structopt(long, required_unless("config"))]
    pub chain_id: Option<ChainId>,
    #[structopt(flatten)]
    pub validator_backend: ValidatorBackend,
}

impl ValidatorConfig {
    pub fn config(&self) -> Result<Config, Error> {
        self.config
            .load()?
            .override_chain_id(self.chain_id)
            .override_validator_backend(&self.validator_backend.validator_backend)
    }

    pub fn build_transaction(
        &self,
        sequence_number: u64,
        fullnode_address: NetworkAddress,
        validator_address: NetworkAddress,
        reconfigure: bool,
        disable_address_validation: bool,
    ) -> Result<Transaction, Error> {
        let config = self.config()?;
        let storage = Storage::from(&config.validator_backend);
        let chain_id = config.chain_id;

        build_validator_config_transaction(
            storage,
            chain_id,
            sequence_number,
            fullnode_address,
            validator_address,
            reconfigure,
            disable_address_validation,
        )
        .map_err(|e| {
            Error::UnexpectedError(format!(
                "Error building validator config transaction: {}",
                e
            ))
        })
    }
}

/// Requires that the validator storage has the following keys set:
/// * OWNER_ACCOUNT
/// * CONSENSUS_KEY
/// * FULLNODE_NETWORK_KEY
/// * VALIDATOR_NETWORK_KEY
/// * VALIDATOR_NETWORK_ADDRESS_KEYS - For encrypting network addresses
/// * OPERATOR_ACCOUNT
/// * OPERATOR_KEY
pub fn build_validator_config_transaction<S: KVStorage + CryptoStorage>(
    mut validator_storage: S,
    chain_id: ChainId,
    sequence_number: u64,
    fullnode_address: NetworkAddress,
    validator_address: NetworkAddress,
    reconfigure: bool,
    disable_address_validation: bool,
) -> anyhow::Result<Transaction> {
    if !disable_address_validation {
        // Verify addresses
        validate_address("validator address", &validator_address)?;
        validate_address("fullnode address", &fullnode_address)?;
    }

    let owner_account = validator_storage
        .get::<AccountAddress>(OWNER_ACCOUNT)
        .map(|v| v.value)?;
    let operator_account = validator_storage
        .get::<AccountAddress>(OPERATOR_ACCOUNT)
        .map(|v| v.value)?;

    let consensus_key = validator_storage
        .get_public_key(CONSENSUS_KEY)
        .map(|v| v.public_key)?;
    let fullnode_network_key = validator_storage
        .get_public_key(FULLNODE_NETWORK_KEY)
        .map(|v| v.public_key)
        .map_err(|e| Error::UnexpectedError(e.to_string()))
        .and_then(to_x25519)?;
    let validator_network_key = validator_storage
        .get_public_key(VALIDATOR_NETWORK_KEY)
        .map(|v| v.public_key)
        .map_err(|e| Error::UnexpectedError(e.to_string()))
        .and_then(to_x25519)?;

    // Build Validator address including protocols and encryption
    // Append ln-noise-ik and ln-handshake protocols to base network addresses
    // and encrypt the validator address.
    let validator_address =
        validator_address.append_prod_protos(validator_network_key, HANDSHAKE_VERSION);
    let encryptor = Encryptor::new(&mut validator_storage);
    let validator_addresses = encryptor
        .encrypt(
            &[validator_address],
            owner_account,
            sequence_number + if reconfigure { 1 } else { 0 },
        )
        .map_err(|e| {
            Error::UnexpectedError(format!("Error encrypting validator address: {}", e))
        })?;

    // Build Fullnode address including protocols
    let fullnode_address =
        fullnode_address.append_prod_protos(fullnode_network_key, HANDSHAKE_VERSION);

    // Generate the validator config script
    let transaction_callback = if reconfigure {
        transaction_builder::encode_set_validator_config_and_reconfigure_script_function
    } else {
        transaction_builder::encode_register_validator_config_script_function
    };
    let validator_config_script = transaction_callback(
        owner_account,
        consensus_key.to_bytes().to_vec(),
        validator_addresses,
        bcs::to_bytes(&vec![fullnode_address]).unwrap(),
    )
    .into_script_function();

    // Create and sign the validator-config transaction
    let raw_txn = build_raw_transaction(
        chain_id,
        operator_account,
        sequence_number,
        validator_config_script,
    );
    let public_key = validator_storage
        .get_public_key(OPERATOR_KEY)
        .map(|v| v.public_key)?;
    let signature = validator_storage.sign(OPERATOR_KEY, &raw_txn)?;
    let signed_txn = SignedTransaction::new(raw_txn, public_key, signature);
    let txn = Transaction::UserTransaction(signed_txn);

    Ok(txn)
}

/// Validates an address to have a DNS/IP and a port, as well as to be resolvable
pub fn validate_address(
    address_name: &'static str,
    network_address: &NetworkAddress,
) -> Result<(), Error> {
    let mut has_addr = false;
    let mut has_port = false;
    // Only allow DNS and IP addresses
    for protocol in network_address.as_slice().iter() {
        match protocol {
            Protocol::Ip4(_) => has_addr = true,
            Protocol::Dns4(dns_name) => {
                let dns_name = format!("{}", dns_name);
                if Ipv4Addr::from_str(&dns_name).is_ok() {
                    return Err(Error::CommandArgumentError(format!(
                        "{}: Please use the /ip4/ protocol for IP addresses",
                        address_name
                    )));
                }
                has_addr = true
            }
            Protocol::Tcp(_) => has_port = true,
            Protocol::Dns(_) | Protocol::Ip6(_) | Protocol::Dns6(_) => {
                return Err(Error::CommandArgumentError(format!(
                    "{}: IPv6 is currently not supported.  Protocol: '{}'",
                    address_name, protocol
                )))
            }
            _ => {
                return Err(Error::CommandArgumentError(format!(
                    "{}: Invalid protocol '{}'",
                    address_name, protocol
                )))
            }
        }
    }

    if !has_addr || !has_port {
        return Err(Error::CommandArgumentError(format!(
            "{}: Address must have a scheme (e.g. /ipv4/) and a port (e.g. /tcp/)",
            address_name
        )));
    }

    // Ensure that the address resolves to IP addresses
    let addrs = network_address.to_socket_addrs().map_err(|err| {
        Error::CommandArgumentError(format!(
            "{}: Failed to resolve address '{}': {}",
            address_name, network_address, err
        ))
    })?;

    if addrs.len() < 1 {
        return Err(Error::CommandArgumentError(format!(
            "{}: Resolved to no IP addresses '{}'",
            address_name, network_address
        )));
    }

    Ok(())
}

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

    #[test]
    fn test_invalid_inputs() {
        let no_port = NetworkAddress::from_str("/ip4/127.0.0.1").unwrap();
        let no_ip = NetworkAddress::from_str("/tcp/1234").unwrap();
        let ipv6 = NetworkAddress::from_str("/dns6/localhost").unwrap();
        let ipv4_and_ipv6 = NetworkAddress::from_str("/dns/localhost").unwrap();
        let bad_protocol = NetworkAddress::from_str("/ln-handshake/0").unwrap();
        let ip_in_dns = NetworkAddress::from_str("/dns4/127.0.0.1/tcp/1234").unwrap();

        validate_address("no_port", &no_port).expect_err("Failed to check for port");
        validate_address("no_ip", &no_ip).expect_err("Failed to check for no IP");
        validate_address("ipv6", &ipv6).expect_err("Failed to check for ipv6");
        validate_address("ipv4_and_ipv6", &ipv4_and_ipv6).expect_err("Failed to check for ipv6");
        validate_address("bad_protocol", &bad_protocol)
            .expect_err("Failed to check for bad protocol");
        validate_address("ip_in_dns", &ip_in_dns).expect_err("Failed to check for ip in DNS");
    }

    #[test]
    fn test_valid_inputs() {
        let ip = NetworkAddress::from_str("/ip4/127.0.0.1/tcp/1234").unwrap();
        let dns = NetworkAddress::from_str("/dns4/localhost/tcp/1234").unwrap();

        validate_address("ip", &ip).expect("IP failed to validate");
        validate_address("dns", &dns).expect("DNS failed to validate");
    }
}
<|endoftext|>


<commit_before>use descartes::{N, V2, P2, Norm, Segment, FiniteCurve, WithUniqueOrthogonal, RelativeToBasis, RoughlyComparable};
use kay::{Swarm, CVec, Recipient, CreateWith, ActorSystem, Individual, Fate};
use core::merge_groups::MergeGroups;
use itertools::Itertools;

mod plan;
mod road_stroke;
mod road_stroke_node_interactable;
mod road_stroke_canvas;
pub mod materialized_reality;
pub mod current_plan_rendering;

pub use self::plan::{Plan, RoadStrokeRef, IntersectionRef, InbetweenStrokeRef, PlanDelta, PlanResult, PlanResultDelta, RemainingOldStrokes};
pub use self::road_stroke::{RoadStroke, RoadStrokeNode, RoadStrokeNodeRef};
pub use self::road_stroke_node_interactable::RoadStrokeNodeInteractable;
pub use self::road_stroke_canvas::RoadStrokeCanvas;
use self::materialized_reality::MaterializedReality;
pub use self::road_stroke::MIN_NODE_DISTANCE;

#[derive(Compact, Clone, Default)]
pub struct CurrentPlan {
    delta: PlanDelta,
    pub current_remaining_old_strokes: RemainingOldStrokes,
    pub current_plan_result: PlanResult,
    pub current_plan_result_delta: PlanResultDelta,
    ui_state: PlanUIState
}
impl Individual for CurrentPlan{}

#[derive(Compact, Clone)]
enum PlanControl{
    AddRoadStrokeNode(P2),
    MoveRoadStrokeNodesTo(CVec<RoadStrokeNodeRef>, P2, P2),
    MaybeMakeCurrent(CVec<RoadStrokeNodeRef>, P2),
    ModifyRemainingOld(CVec<RoadStrokeRef>),
    Materialize(())
}

const FINISH_STROKE_TOLERANCE : f32 = 5.0;

use self::materialized_reality::Simulate;
use self::materialized_reality::Apply;

impl Recipient<PlanControl> for CurrentPlan {
    fn receive(&mut self, msg: &PlanControl) -> Fate {match *msg{
        PlanControl::AddRoadStrokeNode(position) => {
            self.ui_state.drawing_status = match self.ui_state.drawing_status.clone() {
                DrawingStatus::Nothing(_) => {
                    DrawingStatus::WithStartPoint(position)
                },
                DrawingStatus::WithStartPoint(start) => {
                    if (position - start).norm() < FINISH_STROKE_TOLERANCE {
                        DrawingStatus::Nothing(())
                    } else if self.ui_state.create_both_sides {
                        let offset = (position - start).normalize().orthogonal() * 5.0;
                        self.delta.new_strokes.push(RoadStroke::new(vec![
                            RoadStrokeNode{position: start + offset, direction: (position - start).normalize()},
                            RoadStrokeNode{position: position + offset, direction: (position - start).normalize()}
                        ].into()));
                        self.delta.new_strokes.push(RoadStroke::new(vec![
                            RoadStrokeNode{position: position - offset, direction: (start - position).normalize()},
                            RoadStrokeNode{position: start - offset, direction: (start - position).normalize()},
                        ].into()));
                        DrawingStatus::WithCurrentNodes(
                            vec![
                                RoadStrokeNodeRef(self.delta.new_strokes.len() - 2, 1),
                                RoadStrokeNodeRef(self.delta.new_strokes.len() - 1, 0)
                            ].into(),
                            position
                        )
                    } else {
                        self.delta.new_strokes.push(RoadStroke::new(vec![
                            RoadStrokeNode{position: start, direction: (position - start).normalize()},
                            RoadStrokeNode{position: position, direction: (position - start).normalize()}
                        ].into()));
                        DrawingStatus::WithCurrentNodes(
                            vec![RoadStrokeNodeRef(self.delta.new_strokes.len() - 1, 1)].into(),
                            position
                        )
                    }
                },
                DrawingStatus::WithCurrentNodes(current_nodes, previous_add) => {
                    if (position - previous_add).norm() < FINISH_STROKE_TOLERANCE {
                        DrawingStatus::Nothing(())
                    } else {
                        let new_current_nodes = current_nodes.clone().iter().map(|&RoadStrokeNodeRef(stroke_idx, node_idx)| {
                            let stroke = &mut self.delta.new_strokes[stroke_idx];
                            let node = stroke.nodes[node_idx];
                            let relative_position_in_basis = (node.position - previous_add).to_basis(node.direction);

                            if node_idx == stroke.nodes.len() - 1 {
                                // append
                                let new_direction = Segment::arc_with_direction(previous_add, node.direction, position).end_direction();
                                stroke.nodes.push(RoadStrokeNode{
                                    position: position + relative_position_in_basis.from_basis(new_direction),
                                    direction: new_direction
                                });
                                RoadStrokeNodeRef(stroke_idx, stroke.nodes.len() - 1)
                            } else if node_idx == 0 {
                                // prepend
                                let new_direction = -Segment::arc_with_direction(previous_add, -node.direction, position).end_direction();
                                stroke.nodes.insert(0, RoadStrokeNode{
                                    position: position + relative_position_in_basis.from_basis(new_direction),
                                    direction: new_direction
                                });
                                RoadStrokeNodeRef(stroke_idx, 0)
                            } else {unreachable!()}
                        }).collect();

                        DrawingStatus::WithCurrentNodes(new_current_nodes, position)
                    }
                }
            };

            MaterializedReality::id() << Simulate{requester: Self::id(), delta: self.delta.clone(), fresh: false};
            Fate::Live
        },
        PlanControl::MoveRoadStrokeNodesTo(ref node_refs, handle_from, handle_to) =>  {
            for &RoadStrokeNodeRef(stroke_idx, node_idx) in node_refs {
                let stroke = &mut self.delta.new_strokes[stroke_idx];
                let node = stroke.nodes[node_idx];
                if node_idx == stroke.nodes.len() - 1 {
                    let previous_node = stroke.nodes[node_idx - 1];
                    let relative_position_in_basis = (node.position - handle_from).to_basis(node.direction);
                    let previous_node_relative_position = relative_position_in_basis.from_basis(previous_node.direction);
                    let imaginary_previous_add = previous_node.position - previous_node_relative_position;
                    let new_direction = Segment::arc_with_direction(imaginary_previous_add, previous_node.direction, handle_to).end_direction();
                    let new_position = handle_to + relative_position_in_basis.from_basis(new_direction);
                    if (previous_node.position - new_position).norm() > MIN_NODE_DISTANCE {
                        stroke.nodes[node_idx].position = new_position;
                        stroke.nodes[node_idx].direction = new_direction
                    }
                } else if node_idx == 0 {
                    let next_node = stroke.nodes[node_idx + 1];
                    let relative_position_in_basis = (node.position - handle_from).to_basis(node.direction);
                    let next_node_relative_position = relative_position_in_basis.from_basis(next_node.direction);
                    let imaginary_next_add = next_node.position - next_node_relative_position;
                    let new_direction = -Segment::arc_with_direction(imaginary_next_add, -next_node.direction, handle_to).end_direction();
                    let new_position = handle_to + relative_position_in_basis.from_basis(new_direction);
                    if (next_node.position - new_position).norm() > MIN_NODE_DISTANCE {
                        stroke.nodes[node_idx].position = new_position;
                        stroke.nodes[node_idx].direction = new_direction
                    }
                } else {
                    let previous_node = stroke.nodes[node_idx - 1];
                    let next_node = stroke.nodes[node_idx + 1];
                    let new_position = node.position + (handle_to - handle_from);
                    if (previous_node.position - new_position).norm() > MIN_NODE_DISTANCE
                    && (next_node.position - new_position).norm() > MIN_NODE_DISTANCE {
                        stroke.nodes[node_idx].position = new_position;
                    }
                }
            }

            MaterializedReality::id() << Simulate{requester: Self::id(), delta: self.delta.clone(), fresh: false};
            Fate::Live
        },
        PlanControl::MaybeMakeCurrent(ref node_refs, handle_position) => {
            let strokes = &mut self.delta.new_strokes;
            let is_first_or_last = |&RoadStrokeNodeRef(stroke_idx, node_idx)| {
                node_idx == 0 || node_idx == strokes[stroke_idx].nodes.len() - 1
            };

            if node_refs.iter().all(is_first_or_last) {
                self.ui_state.drawing_status = DrawingStatus::WithCurrentNodes(node_refs.clone(), handle_position);
            }
            Fate::Live
        }
        PlanControl::ModifyRemainingOld(ref old_refs) => {
            for old_ref in old_refs {
                let old_stroke = self.current_remaining_old_strokes.mapping.get(*old_ref).unwrap();
                self.delta.strokes_to_destroy.insert(*old_ref, old_stroke.clone());
                self.delta.new_strokes.push(old_stroke.clone());
            }
            MaterializedReality::id() << Simulate{requester: Self::id(), delta: self.delta.clone(), fresh: false};
            Fate::Live
        }
        PlanControl::Materialize(()) => {
            MaterializedReality::id() << Apply{requester: Self::id(), delta: self.delta.clone()};
            *self = CurrentPlan::default();
            Fate::Live
        }
    }}
}

use self::materialized_reality::SimulationResult;

impl Recipient<SimulationResult> for CurrentPlan{
    fn receive(&mut self, msg: &SimulationResult) -> Fate {match *msg{
        SimulationResult{ref remaining_old_strokes, ref result, ref result_delta, fresh} => {
            self.current_remaining_old_strokes = remaining_old_strokes.clone();
            self.current_plan_result = result.clone();
            self.current_plan_result_delta = result_delta.clone();
            self.ui_state.dirty = true;
            if fresh {Self::id() << RecreateInteractables}
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
struct RecreateInteractables;
#[derive(Copy, Clone)]
struct ClearAll;

impl Recipient<RecreateInteractables> for CurrentPlan {
    fn receive(&mut self, _msg: &RecreateInteractables) -> Fate {
        Swarm::<RoadStrokeNodeInteractable>::all() << ClearAll;
        Swarm::<RoadStrokeCanvas>::all() << ClearAll;
        self.create_interactables();
        Fate::Live
    }
}

#[derive(Compact, Clone)]
pub enum InteractableParent{
    New(()),
    WillBecomeNew(CVec<RoadStrokeRef>),
}

impl CurrentPlan{
    fn create_interactables(&self) {
        Swarm::<RoadStrokeCanvas>::all() << CreateWith(RoadStrokeCanvas::new(), AddToUI);
        let new_interactables = self.delta.new_strokes.iter().enumerate().flat_map(|(i, stroke)| {
            stroke.create_interactables(RoadStrokeRef(i), InteractableParent::New(()))
        }).collect::<Vec<_>>();
        let old_interactables = self.current_remaining_old_strokes.mapping.pairs().flat_map(|(old_ref, stroke)| {
            stroke.create_interactables(*old_ref, InteractableParent::WillBecomeNew(
                vec![RoadStrokeRef(self.delta.new_strokes.len())].into()
            ))
        });

        let mut interactable_groups = new_interactables.clone().into_iter().map(
            |interactable| vec![interactable]).collect::<Vec<_>>();
        interactable_groups.merge_groups(|group_1, group_2|
                group_1.iter().cartesian_product(group_2.iter()).any(|(interactable_1, interactable_2)|
                    (interactable_1.position - interactable_2.position).norm() < 20.0
                    && (interactable_1.direction.is_roughly_within(interactable_2.direction, 0.1)
                        || interactable_1.direction.is_roughly_within(-interactable_2.direction, 0.1))
                )
        );

        for interactable in new_interactables.into_iter().chain(old_interactables) {
            Swarm::<RoadStrokeNodeInteractable>::all() << CreateWith(interactable, AddToUI);
        }

        for interactable_group in interactable_groups {
            if interactable_group.len() > 1 {
                let position = (interactable_group.iter().fold(V2::new(0.0, 0.0),
                    |sum, interactable| sum + interactable.position.to_vector()
                ) / (interactable_group.len() as N)).to_point();

                let direction = interactable_group[0].direction;
                let node_refs = interactable_group.iter().flat_map(
                    |interactable| interactable.node_refs.clone()).collect();
                let group_interactable = RoadStrokeNodeInteractable::new(
                    position,
                    direction,
                    node_refs,
                    InteractableParent::New(())
                );
                Swarm::<RoadStrokeNodeInteractable>::all() << CreateWith(group_interactable, AddToUI);
            }
        }

    }
}

#[derive(Compact, Clone)]
pub enum DrawingStatus{
    Nothing(()),
    WithStartPoint(P2),
    WithCurrentNodes(CVec<RoadStrokeNodeRef>, P2)
}

#[derive(Compact, Clone)]
struct PlanUIState{
    create_both_sides: bool,
    drawing_status: DrawingStatus,
    dirty: bool
}

impl Default for PlanUIState{
    fn default() -> PlanUIState{
        PlanUIState{
            create_both_sides: true,
            drawing_status: DrawingStatus::Nothing(()),
            dirty: true
        }
    }
}

#[derive(Copy, Clone)]
struct AddToUI;

pub fn setup(system: &mut ActorSystem) {
    system.add_individual(CurrentPlan::default());
    system.add_inbox::<PlanControl, CurrentPlan>();
    system.add_inbox::<SimulationResult, CurrentPlan>();
    system.add_inbox::<RecreateInteractables, CurrentPlan>();
    self::materialized_reality::setup(system);
    self::road_stroke_node_interactable::setup(system);
    self::road_stroke_canvas::setup(system);
}<commit_msg>Multi-lane roads #6 🛣<commit_after>use descartes::{N, V2, P2, Norm, Segment, FiniteCurve, WithUniqueOrthogonal, RelativeToBasis, RoughlyComparable};
use kay::{Swarm, CVec, Recipient, CreateWith, ActorSystem, Individual, Fate};
use core::merge_groups::MergeGroups;
use itertools::Itertools;

mod plan;
mod road_stroke;
mod road_stroke_node_interactable;
mod road_stroke_canvas;
pub mod materialized_reality;
pub mod current_plan_rendering;

pub use self::plan::{Plan, RoadStrokeRef, IntersectionRef, InbetweenStrokeRef, PlanDelta, PlanResult, PlanResultDelta, RemainingOldStrokes};
pub use self::road_stroke::{RoadStroke, RoadStrokeNode, RoadStrokeNodeRef};
pub use self::road_stroke_node_interactable::RoadStrokeNodeInteractable;
pub use self::road_stroke_canvas::RoadStrokeCanvas;
use self::materialized_reality::MaterializedReality;
pub use self::road_stroke::MIN_NODE_DISTANCE;

#[derive(Compact, Clone, Default)]
pub struct CurrentPlan {
    delta: PlanDelta,
    pub current_remaining_old_strokes: RemainingOldStrokes,
    pub current_plan_result: PlanResult,
    pub current_plan_result_delta: PlanResultDelta,
    ui_state: PlanUIState
}
impl Individual for CurrentPlan{}

#[derive(Compact, Clone)]
enum PlanControl{
    AddRoadStrokeNode(P2),
    MoveRoadStrokeNodesTo(CVec<RoadStrokeNodeRef>, P2, P2),
    MaybeMakeCurrent(CVec<RoadStrokeNodeRef>, P2),
    ModifyRemainingOld(CVec<RoadStrokeRef>),
    Materialize(())
}

const FINISH_STROKE_TOLERANCE : f32 = 5.0;

use self::materialized_reality::Simulate;
use self::materialized_reality::Apply;

impl Recipient<PlanControl> for CurrentPlan {
    fn receive(&mut self, msg: &PlanControl) -> Fate {match *msg{
        PlanControl::AddRoadStrokeNode(position) => {
            self.ui_state.drawing_status = match self.ui_state.drawing_status.clone() {
                DrawingStatus::Nothing(_) => {
                    DrawingStatus::WithStartPoint(position)
                },
                DrawingStatus::WithStartPoint(start) => {
                    if (position - start).norm() < FINISH_STROKE_TOLERANCE {
                        DrawingStatus::Nothing(())
                    } else {
                        let new_node_refs = (0..self.ui_state.n_lanes_per_side).into_iter().flat_map(|lane_idx| {
                            let offset = (position - start).normalize().orthogonal() * (5.0 + 10.0 * lane_idx as N);

                            self.delta.new_strokes.push(RoadStroke::new(vec![
                                RoadStrokeNode{position: start + offset, direction: (position - start).normalize()},
                                RoadStrokeNode{position: position + offset, direction: (position - start).normalize()}
                            ].into()));
                            let right_lane_node_ref = RoadStrokeNodeRef(self.delta.new_strokes.len() - 1, 1);

                            if self.ui_state.create_both_sides {
                                self.delta.new_strokes.push(RoadStroke::new(vec![
                                    RoadStrokeNode{position: position - offset, direction: (start - position).normalize()},
                                    RoadStrokeNode{position: start - offset, direction: (start - position).normalize()},
                                ].into()));
                                let left_lane_node_ref = RoadStrokeNodeRef(self.delta.new_strokes.len() - 1, 0);
                                vec![right_lane_node_ref, left_lane_node_ref]
                            } else {
                                vec![right_lane_node_ref]
                            }
                        });
                        DrawingStatus::WithCurrentNodes(new_node_refs.collect(), position)
                    }
                },
                DrawingStatus::WithCurrentNodes(current_nodes, previous_add) => {
                    if (position - previous_add).norm() < FINISH_STROKE_TOLERANCE {
                        DrawingStatus::Nothing(())
                    } else {
                        let new_current_nodes = current_nodes.clone().iter().map(|&RoadStrokeNodeRef(stroke_idx, node_idx)| {
                            let stroke = &mut self.delta.new_strokes[stroke_idx];
                            let node = stroke.nodes[node_idx];
                            let relative_position_in_basis = (node.position - previous_add).to_basis(node.direction);

                            if node_idx == stroke.nodes.len() - 1 {
                                // append
                                let new_direction = Segment::arc_with_direction(previous_add, node.direction, position).end_direction();
                                stroke.nodes.push(RoadStrokeNode{
                                    position: position + relative_position_in_basis.from_basis(new_direction),
                                    direction: new_direction
                                });
                                RoadStrokeNodeRef(stroke_idx, stroke.nodes.len() - 1)
                            } else if node_idx == 0 {
                                // prepend
                                let new_direction = -Segment::arc_with_direction(previous_add, -node.direction, position).end_direction();
                                stroke.nodes.insert(0, RoadStrokeNode{
                                    position: position + relative_position_in_basis.from_basis(new_direction),
                                    direction: new_direction
                                });
                                RoadStrokeNodeRef(stroke_idx, 0)
                            } else {unreachable!()}
                        }).collect();

                        DrawingStatus::WithCurrentNodes(new_current_nodes, position)
                    }
                }
            };

            MaterializedReality::id() << Simulate{requester: Self::id(), delta: self.delta.clone(), fresh: false};
            Fate::Live
        },
        PlanControl::MoveRoadStrokeNodesTo(ref node_refs, handle_from, handle_to) =>  {
            for &RoadStrokeNodeRef(stroke_idx, node_idx) in node_refs {
                let stroke = &mut self.delta.new_strokes[stroke_idx];
                let node = stroke.nodes[node_idx];
                if node_idx == stroke.nodes.len() - 1 {
                    let previous_node = stroke.nodes[node_idx - 1];
                    let relative_position_in_basis = (node.position - handle_from).to_basis(node.direction);
                    let previous_node_relative_position = relative_position_in_basis.from_basis(previous_node.direction);
                    let imaginary_previous_add = previous_node.position - previous_node_relative_position;
                    let new_direction = Segment::arc_with_direction(imaginary_previous_add, previous_node.direction, handle_to).end_direction();
                    let new_position = handle_to + relative_position_in_basis.from_basis(new_direction);
                    if (previous_node.position - new_position).norm() > MIN_NODE_DISTANCE {
                        stroke.nodes[node_idx].position = new_position;
                        stroke.nodes[node_idx].direction = new_direction
                    }
                } else if node_idx == 0 {
                    let next_node = stroke.nodes[node_idx + 1];
                    let relative_position_in_basis = (node.position - handle_from).to_basis(node.direction);
                    let next_node_relative_position = relative_position_in_basis.from_basis(next_node.direction);
                    let imaginary_next_add = next_node.position - next_node_relative_position;
                    let new_direction = -Segment::arc_with_direction(imaginary_next_add, -next_node.direction, handle_to).end_direction();
                    let new_position = handle_to + relative_position_in_basis.from_basis(new_direction);
                    if (next_node.position - new_position).norm() > MIN_NODE_DISTANCE {
                        stroke.nodes[node_idx].position = new_position;
                        stroke.nodes[node_idx].direction = new_direction
                    }
                } else {
                    let previous_node = stroke.nodes[node_idx - 1];
                    let next_node = stroke.nodes[node_idx + 1];
                    let new_position = node.position + (handle_to - handle_from);
                    if (previous_node.position - new_position).norm() > MIN_NODE_DISTANCE
                    && (next_node.position - new_position).norm() > MIN_NODE_DISTANCE {
                        stroke.nodes[node_idx].position = new_position;
                    }
                }
            }

            MaterializedReality::id() << Simulate{requester: Self::id(), delta: self.delta.clone(), fresh: false};
            Fate::Live
        },
        PlanControl::MaybeMakeCurrent(ref node_refs, handle_position) => {
            let strokes = &mut self.delta.new_strokes;
            let is_first_or_last = |&RoadStrokeNodeRef(stroke_idx, node_idx)| {
                node_idx == 0 || node_idx == strokes[stroke_idx].nodes.len() - 1
            };

            if node_refs.iter().all(is_first_or_last) {
                self.ui_state.drawing_status = DrawingStatus::WithCurrentNodes(node_refs.clone(), handle_position);
            }
            Fate::Live
        }
        PlanControl::ModifyRemainingOld(ref old_refs) => {
            for old_ref in old_refs {
                let old_stroke = self.current_remaining_old_strokes.mapping.get(*old_ref).unwrap();
                self.delta.strokes_to_destroy.insert(*old_ref, old_stroke.clone());
                self.delta.new_strokes.push(old_stroke.clone());
            }
            MaterializedReality::id() << Simulate{requester: Self::id(), delta: self.delta.clone(), fresh: false};
            Fate::Live
        }
        PlanControl::Materialize(()) => {
            MaterializedReality::id() << Apply{requester: Self::id(), delta: self.delta.clone()};
            *self = CurrentPlan::default();
            Fate::Live
        }
    }}
}

use self::materialized_reality::SimulationResult;

impl Recipient<SimulationResult> for CurrentPlan{
    fn receive(&mut self, msg: &SimulationResult) -> Fate {match *msg{
        SimulationResult{ref remaining_old_strokes, ref result, ref result_delta, fresh} => {
            self.current_remaining_old_strokes = remaining_old_strokes.clone();
            self.current_plan_result = result.clone();
            self.current_plan_result_delta = result_delta.clone();
            self.ui_state.dirty = true;
            if fresh {Self::id() << RecreateInteractables}
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
struct RecreateInteractables;
#[derive(Copy, Clone)]
struct ClearAll;

impl Recipient<RecreateInteractables> for CurrentPlan {
    fn receive(&mut self, _msg: &RecreateInteractables) -> Fate {
        Swarm::<RoadStrokeNodeInteractable>::all() << ClearAll;
        Swarm::<RoadStrokeCanvas>::all() << ClearAll;
        self.create_interactables();
        Fate::Live
    }
}

#[derive(Compact, Clone)]
pub enum InteractableParent{
    New(()),
    WillBecomeNew(CVec<RoadStrokeRef>),
}

impl CurrentPlan{
    fn create_interactables(&self) {
        Swarm::<RoadStrokeCanvas>::all() << CreateWith(RoadStrokeCanvas::new(), AddToUI);
        let new_interactables = self.delta.new_strokes.iter().enumerate().flat_map(|(i, stroke)| {
            stroke.create_interactables(RoadStrokeRef(i), InteractableParent::New(()))
        }).collect::<Vec<_>>();
        let old_interactables = self.current_remaining_old_strokes.mapping.pairs().flat_map(|(old_ref, stroke)| {
            stroke.create_interactables(*old_ref, InteractableParent::WillBecomeNew(
                vec![RoadStrokeRef(self.delta.new_strokes.len())].into()
            ))
        });

        let mut interactable_groups = new_interactables.clone().into_iter().map(
            |interactable| vec![interactable]).collect::<Vec<_>>();
        interactable_groups.merge_groups(|group_1, group_2|
                group_1.iter().cartesian_product(group_2.iter()).any(|(interactable_1, interactable_2)|
                    (interactable_1.position - interactable_2.position).norm() < 20.0
                    && (interactable_1.direction.is_roughly_within(interactable_2.direction, 0.1)
                        || interactable_1.direction.is_roughly_within(-interactable_2.direction, 0.1))
                )
        );

        for interactable in new_interactables.into_iter().chain(old_interactables) {
            Swarm::<RoadStrokeNodeInteractable>::all() << CreateWith(interactable, AddToUI);
        }

        for interactable_group in interactable_groups {
            if interactable_group.len() > 1 {
                let position = (interactable_group.iter().fold(V2::new(0.0, 0.0),
                    |sum, interactable| sum + interactable.position.to_vector()
                ) / (interactable_group.len() as N)).to_point();

                let direction = interactable_group[0].direction;
                let node_refs = interactable_group.iter().flat_map(
                    |interactable| interactable.node_refs.clone()).collect();
                let group_interactable = RoadStrokeNodeInteractable::new(
                    position,
                    direction,
                    node_refs,
                    InteractableParent::New(())
                );
                Swarm::<RoadStrokeNodeInteractable>::all() << CreateWith(group_interactable, AddToUI);
            }
        }

    }
}

#[derive(Compact, Clone)]
pub enum DrawingStatus{
    Nothing(()),
    WithStartPoint(P2),
    WithCurrentNodes(CVec<RoadStrokeNodeRef>, P2)
}

#[derive(Compact, Clone)]
struct PlanUIState{
    create_both_sides: bool,
    n_lanes_per_side: usize,
    drawing_status: DrawingStatus,
    dirty: bool
}

impl Default for PlanUIState{
    fn default() -> PlanUIState{
        PlanUIState{
            create_both_sides: true,
            n_lanes_per_side: 2,
            drawing_status: DrawingStatus::Nothing(()),
            dirty: true
        }
    }
}

#[derive(Copy, Clone)]
struct AddToUI;

pub fn setup(system: &mut ActorSystem) {
    system.add_individual(CurrentPlan::default());
    system.add_inbox::<PlanControl, CurrentPlan>();
    system.add_inbox::<SimulationResult, CurrentPlan>();
    system.add_inbox::<RecreateInteractables, CurrentPlan>();
    self::materialized_reality::setup(system);
    self::road_stroke_node_interactable::setup(system);
    self::road_stroke_canvas::setup(system);
}<|endoftext|>


<commit_before>//! An example showing off the usage of `Deserialize` to automatically decode
//! TOML into a Rust `struct`, with enums.

#![deny(warnings)]

extern crate toml;
#[macro_use]
extern crate serde_derive;

/// This is what we're going to decode into.
#[derive(Debug, Deserialize)]
struct Config {
    plain: MyEnum,
    // tuple: MyEnum,
    #[serde(rename = "struct")]
    structv: MyEnum,
    my_enum: Vec<MyEnum>,
}

#[derive(Debug, Deserialize)]
enum MyEnum {
    Plain,
    Tuple(i64, bool),
    Struct { value: i64 },
}

fn main() {
    let toml_str = r#"
    plain = "Plain"
    # tuple = { 0 = 123, 1 = true }
    struct = { Struct = { value = 123 } }
    my_enum = [
        { Plain = {} },
        # { Tuple = { 0 = 123, 1 = true } },
        { Struct = { value = 123 } }
    ]"#;

    let decoded: Config = toml::from_str(toml_str).unwrap();
    println!("{:#?}", decoded);
}
<commit_msg>Added `NewType` variant to example.<commit_after>//! An example showing off the usage of `Deserialize` to automatically decode
//! TOML into a Rust `struct`, with enums.

#![deny(warnings)]

extern crate toml;
#[macro_use]
extern crate serde_derive;

/// This is what we're going to decode into.
#[derive(Debug, Deserialize)]
struct Config {
    plain: MyEnum,
    // tuple: MyEnum,
    #[serde(rename = "struct")]
    structv: MyEnum,
    newtype: MyEnum,
    my_enum: Vec<MyEnum>,
}

#[derive(Debug, Deserialize)]
enum MyEnum {
    Plain,
    Tuple(i64, bool),
    NewType(String),
    Struct { value: i64 },
}

fn main() {
    let toml_str = r#"
    plain = "Plain"
    # tuple = { 0 = 123, 1 = true }
    struct = { Struct = { value = 123 } }
    newtype = { NewType = "value" }
    my_enum = [
        { Plain = {} },
        # { Tuple = { 0 = 123, 1 = true } },
        { NewType = "value" },
        { Struct = { value = 123 } }
    ]"#;

    let decoded: Config = toml::from_str(toml_str).unwrap();
    println!("{:#?}", decoded);
}
<|endoftext|>


<commit_before>//! # The Rust Core Library
//!
//! The Rust Core Library is the dependency-free[^free] foundation of [The
//! Rust Standard Library](../std/index.html). It is the portable glue
//! between the language and its libraries, defining the intrinsic and
//! primitive building blocks of all Rust code. It links to no
//! upstream libraries, no system libraries, and no libc.
//!
//! [^free]: Strictly speaking, there are some symbols which are needed but
//!          they aren't always necessary.
//!
//! The core library is *minimal*: it isn't even aware of heap allocation,
//! nor does it provide concurrency or I/O. These things require
//! platform integration, and this library is platform-agnostic.
//!
//! # How to use the core library
//!
//! Please note that all of these details are currently not considered stable.
//!
// FIXME: Fill me in with more detail when the interface settles
//! This library is built on the assumption of a few existing symbols:
//!
//! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
//!   often generated by LLVM. Additionally, this library can make explicit
//!   calls to these functions. Their signatures are the same as found in C.
//!   These functions are often provided by the system libc, but can also be
//!   provided by the [compiler-builtins crate](https://crates.io/crates/compiler_builtins).
//!
//! * `rust_begin_panic` - This function takes four arguments, a
//!   `fmt::Arguments`, a `&'static str`, and two `u32`'s. These four arguments
//!   dictate the panic message, the file at which panic was invoked, and the
//!   line and column inside the file. It is up to consumers of this core
//!   library to define this panic function; it is only required to never
//!   return. This requires a `lang` attribute named `panic_impl`.
//!
//! * `rust_eh_personality` - is used by the failure mechanisms of the
//!    compiler. This is often mapped to GCC's personality function, but crates
//!    which do not trigger a panic can be assured that this function is never
//!    called. The `lang` attribute is called `eh_personality`.

// Since libcore defines many fundamental lang items, all tests live in a
// separate crate, libcoretest, to avoid bizarre issues.
//
// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do
// this, both the generated test artifact and the linked libtest (which
// transitively includes libcore) will both define the same set of lang items,
// and this will cause the E0152 "found duplicate lang item" error. See
// discussion in #50466 for details.
//
// This cfg won't affect doc tests.
#![cfg(not(test))]
#![stable(feature = "core", since = "1.6.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(deny(warnings))),
    test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
#![no_core]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(bound_cloned)]
#![feature(cfg_target_has_atomic)]
#![feature(concat_idents)]
#![feature(const_alloc_layout)]
#![feature(const_discriminant)]
#![feature(const_checked_int_methods)]
#![feature(const_euclidean_int_methods)]
#![feature(const_float_classify)]
#![feature(const_float_bits_conv)]
#![feature(const_overflowing_int_methods)]
#![feature(const_int_unchecked_arith)]
#![feature(const_int_pow)]
#![feature(constctlz)]
#![feature(const_panic)]
#![feature(const_fn_union)]
#![feature(const_generics)]
#![feature(const_option)]
#![feature(const_precise_live_drops)]
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
#![feature(const_raw_ptr_comparison)]
#![feature(const_result)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_slice_ptr_len)]
#![feature(const_size_of_val)]
#![feature(const_align_of_val)]
#![feature(const_type_name)]
#![feature(const_likely)]
#![feature(const_unreachable_unchecked)]
#![feature(custom_inner_attributes)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(duration_consts_2)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
#![feature(try_find)]
#![feature(is_sorted)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(llvm_asm)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(nll)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(optin_builtin_traits)]
#![feature(or_patterns)]
#![feature(prelude_import)]
#![feature(ptr_as_uninit)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(simd_ffi)]
#![feature(min_specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
#![feature(transparent_unions)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(variant_count)]
#![feature(doc_alias)]
#![feature(mmx_target_feature)]
#![feature(tbm_target_feature)]
#![feature(sse4a_target_feature)]
#![feature(arm_target_feature)]
#![feature(powerpc_target_feature)]
#![feature(mips_target_feature)]
#![feature(aarch64_target_feature)]
#![feature(wasm_target_feature)]
#![feature(avx512_target_feature)]
#![feature(cmpxchg16b_target_feature)]
#![feature(rtm_target_feature)]
#![feature(f16c_target_feature)]
#![feature(hexagon_target_feature)]
#![feature(const_fn_transmute)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_extra)]
#![feature(external_doc)]
#![feature(associated_type_bounds)]
#![feature(const_caller_location)]
#![feature(slice_ptr_get)]
#![feature(no_niche)] // rust-lang/rust#68303
#![feature(unsafe_block_in_unsafe_fn)]
#![deny(unsafe_op_in_unsafe_fn)]

#[prelude_import]
#[allow(unused)]
use prelude::v1::*;

#[cfg(not(test))] // See #65860
#[macro_use]
mod macros;

#[macro_use]
mod internal_macros;

#[path = "num/int_macros.rs"]
#[macro_use]
mod int_macros;

#[path = "num/i128.rs"]
pub mod i128;
#[path = "num/i16.rs"]
pub mod i16;
#[path = "num/i32.rs"]
pub mod i32;
#[path = "num/i64.rs"]
pub mod i64;
#[path = "num/i8.rs"]
pub mod i8;
#[path = "num/isize.rs"]
pub mod isize;

#[path = "num/u128.rs"]
pub mod u128;
#[path = "num/u16.rs"]
pub mod u16;
#[path = "num/u32.rs"]
pub mod u32;
#[path = "num/u64.rs"]
pub mod u64;
#[path = "num/u8.rs"]
pub mod u8;
#[path = "num/usize.rs"]
pub mod usize;

#[path = "num/f32.rs"]
pub mod f32;
#[path = "num/f64.rs"]
pub mod f64;

#[macro_use]
pub mod num;

/* The libcore prelude, not as all-encompassing as the libstd prelude */

pub mod prelude;

/* Core modules for ownership management */

pub mod hint;
pub mod intrinsics;
pub mod mem;
pub mod ptr;

/* Core language traits */

pub mod borrow;
#[cfg(not(test))] // See #65860
pub mod clone;
#[cfg(not(test))] // See #65860
pub mod cmp;
pub mod convert;
#[cfg(not(test))] // See #65860
pub mod default;
#[cfg(not(test))] // See #65860
pub mod marker;
pub mod ops;

/* Core types and methods on primitives */

pub mod any;
#[cfg(not(test))] // See #65860
pub mod array;
pub mod ascii;
pub mod cell;
pub mod char;
pub mod ffi;
#[cfg(not(test))] // See #65860
pub mod iter;
#[unstable(feature = "once_cell", issue = "74465")]
pub mod lazy;
pub mod option;
pub mod panic;
pub mod panicking;
#[cfg(not(test))] // See #65860
pub mod pin;
pub mod raw;
pub mod result;
pub mod sync;

#[cfg(not(test))] // See #65860
pub mod fmt;
#[cfg(not(test))] // See #65860
pub mod hash;
pub mod slice;
#[cfg(not(test))] // See #65860
pub mod str;
pub mod time;

pub mod unicode;

/* Async */
#[cfg(not(test))] // See #65860
pub mod future;
pub mod task;

/* Heap memory allocator trait */
#[allow(missing_docs)]
pub mod alloc;

// note: does not need to be public
mod bool;
mod tuple;
mod unit;

#[stable(feature = "core_primitive", since = "1.43.0")]
pub mod primitive;

// Pull in the `core_arch` crate directly into libcore. The contents of
// `core_arch` are in a different repository: rust-lang/stdarch.
//
// `core_arch` depends on libcore, but the contents of this module are
// set up in such a way that directly pulling it here works such that the
// crate uses the this crate as its libcore.
#[path = "../../stdarch/crates/core_arch/src/mod.rs"]
#[allow(
    missing_docs,
    missing_debug_implementations,
    dead_code,
    unused_imports,
    unsafe_op_in_unsafe_fn
)]
// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
#[allow(clashing_extern_declarations)]
#[unstable(feature = "stdsimd", issue = "48556")]
mod core_arch;

#[stable(feature = "simd_arch", since = "1.27.0")]
pub use core_arch::arch;
<commit_msg>Remove unneeded `#[cfg(not(test))]` from libcore<commit_after>//! # The Rust Core Library
//!
//! The Rust Core Library is the dependency-free[^free] foundation of [The
//! Rust Standard Library](../std/index.html). It is the portable glue
//! between the language and its libraries, defining the intrinsic and
//! primitive building blocks of all Rust code. It links to no
//! upstream libraries, no system libraries, and no libc.
//!
//! [^free]: Strictly speaking, there are some symbols which are needed but
//!          they aren't always necessary.
//!
//! The core library is *minimal*: it isn't even aware of heap allocation,
//! nor does it provide concurrency or I/O. These things require
//! platform integration, and this library is platform-agnostic.
//!
//! # How to use the core library
//!
//! Please note that all of these details are currently not considered stable.
//!
// FIXME: Fill me in with more detail when the interface settles
//! This library is built on the assumption of a few existing symbols:
//!
//! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
//!   often generated by LLVM. Additionally, this library can make explicit
//!   calls to these functions. Their signatures are the same as found in C.
//!   These functions are often provided by the system libc, but can also be
//!   provided by the [compiler-builtins crate](https://crates.io/crates/compiler_builtins).
//!
//! * `rust_begin_panic` - This function takes four arguments, a
//!   `fmt::Arguments`, a `&'static str`, and two `u32`'s. These four arguments
//!   dictate the panic message, the file at which panic was invoked, and the
//!   line and column inside the file. It is up to consumers of this core
//!   library to define this panic function; it is only required to never
//!   return. This requires a `lang` attribute named `panic_impl`.
//!
//! * `rust_eh_personality` - is used by the failure mechanisms of the
//!    compiler. This is often mapped to GCC's personality function, but crates
//!    which do not trigger a panic can be assured that this function is never
//!    called. The `lang` attribute is called `eh_personality`.

// Since libcore defines many fundamental lang items, all tests live in a
// separate crate, libcoretest, to avoid bizarre issues.
//
// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do
// this, both the generated test artifact and the linked libtest (which
// transitively includes libcore) will both define the same set of lang items,
// and this will cause the E0152 "found duplicate lang item" error. See
// discussion in #50466 for details.
//
// This cfg won't affect doc tests.
#![cfg(not(test))]
#![stable(feature = "core", since = "1.6.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(deny(warnings))),
    test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
#![no_core]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(bound_cloned)]
#![feature(cfg_target_has_atomic)]
#![feature(concat_idents)]
#![feature(const_alloc_layout)]
#![feature(const_discriminant)]
#![feature(const_checked_int_methods)]
#![feature(const_euclidean_int_methods)]
#![feature(const_float_classify)]
#![feature(const_float_bits_conv)]
#![feature(const_overflowing_int_methods)]
#![feature(const_int_unchecked_arith)]
#![feature(const_int_pow)]
#![feature(constctlz)]
#![feature(const_panic)]
#![feature(const_fn_union)]
#![feature(const_generics)]
#![feature(const_option)]
#![feature(const_precise_live_drops)]
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
#![feature(const_raw_ptr_comparison)]
#![feature(const_result)]
#![feature(const_slice_from_raw_parts)]
#![feature(const_slice_ptr_len)]
#![feature(const_size_of_val)]
#![feature(const_align_of_val)]
#![feature(const_type_name)]
#![feature(const_likely)]
#![feature(const_unreachable_unchecked)]
#![feature(custom_inner_attributes)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(duration_consts_2)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
#![feature(try_find)]
#![feature(is_sorted)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(llvm_asm)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(nll)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(optin_builtin_traits)]
#![feature(or_patterns)]
#![feature(prelude_import)]
#![feature(ptr_as_uninit)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(simd_ffi)]
#![feature(min_specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
#![feature(transparent_unions)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(variant_count)]
#![feature(doc_alias)]
#![feature(mmx_target_feature)]
#![feature(tbm_target_feature)]
#![feature(sse4a_target_feature)]
#![feature(arm_target_feature)]
#![feature(powerpc_target_feature)]
#![feature(mips_target_feature)]
#![feature(aarch64_target_feature)]
#![feature(wasm_target_feature)]
#![feature(avx512_target_feature)]
#![feature(cmpxchg16b_target_feature)]
#![feature(rtm_target_feature)]
#![feature(f16c_target_feature)]
#![feature(hexagon_target_feature)]
#![feature(const_fn_transmute)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_extra)]
#![feature(external_doc)]
#![feature(associated_type_bounds)]
#![feature(const_caller_location)]
#![feature(slice_ptr_get)]
#![feature(no_niche)] // rust-lang/rust#68303
#![feature(unsafe_block_in_unsafe_fn)]
#![deny(unsafe_op_in_unsafe_fn)]

#[prelude_import]
#[allow(unused)]
use prelude::v1::*;

#[cfg(not(test))] // See #65860
#[macro_use]
mod macros;

#[macro_use]
mod internal_macros;

#[path = "num/int_macros.rs"]
#[macro_use]
mod int_macros;

#[path = "num/i128.rs"]
pub mod i128;
#[path = "num/i16.rs"]
pub mod i16;
#[path = "num/i32.rs"]
pub mod i32;
#[path = "num/i64.rs"]
pub mod i64;
#[path = "num/i8.rs"]
pub mod i8;
#[path = "num/isize.rs"]
pub mod isize;

#[path = "num/u128.rs"]
pub mod u128;
#[path = "num/u16.rs"]
pub mod u16;
#[path = "num/u32.rs"]
pub mod u32;
#[path = "num/u64.rs"]
pub mod u64;
#[path = "num/u8.rs"]
pub mod u8;
#[path = "num/usize.rs"]
pub mod usize;

#[path = "num/f32.rs"]
pub mod f32;
#[path = "num/f64.rs"]
pub mod f64;

#[macro_use]
pub mod num;

/* The libcore prelude, not as all-encompassing as the libstd prelude */

pub mod prelude;

/* Core modules for ownership management */

pub mod hint;
pub mod intrinsics;
pub mod mem;
pub mod ptr;

/* Core language traits */

pub mod borrow;
pub mod clone;
pub mod cmp;
pub mod convert;
pub mod default;
pub mod marker;
pub mod ops;

/* Core types and methods on primitives */

pub mod any;
pub mod array;
pub mod ascii;
pub mod cell;
pub mod char;
pub mod ffi;
pub mod iter;
#[unstable(feature = "once_cell", issue = "74465")]
pub mod lazy;
pub mod option;
pub mod panic;
pub mod panicking;
pub mod pin;
pub mod raw;
pub mod result;
pub mod sync;

pub mod fmt;
pub mod hash;
pub mod slice;
pub mod str;
pub mod time;

pub mod unicode;

/* Async */
pub mod future;
pub mod task;

/* Heap memory allocator trait */
#[allow(missing_docs)]
pub mod alloc;

// note: does not need to be public
mod bool;
mod tuple;
mod unit;

#[stable(feature = "core_primitive", since = "1.43.0")]
pub mod primitive;

// Pull in the `core_arch` crate directly into libcore. The contents of
// `core_arch` are in a different repository: rust-lang/stdarch.
//
// `core_arch` depends on libcore, but the contents of this module are
// set up in such a way that directly pulling it here works such that the
// crate uses the this crate as its libcore.
#[path = "../../stdarch/crates/core_arch/src/mod.rs"]
#[allow(
    missing_docs,
    missing_debug_implementations,
    dead_code,
    unused_imports,
    unsafe_op_in_unsafe_fn
)]
// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
#[allow(clashing_extern_declarations)]
#[unstable(feature = "stdsimd", issue = "48556")]
mod core_arch;

#[stable(feature = "simd_arch", since = "1.27.0")]
pub use core_arch::arch;
<|endoftext|>


<commit_before>use std;
use servo;

import result::{ok, err};
import std::test::{test_opts, run_tests_console, test_desc};
import std::getopts::{getopts, reqopt, opt_str, fail_str};
import path::{connect, basename};
import os::list_dir_path;
import servo::run_pipeline_png;

fn main(args: ~[~str]) {
    let config = parse_config(args);
    let opts = test_options(config);
    let tests = find_tests(config);
    install_rasterize_py(config);
    run_tests_console(opts, tests);
}

struct Config {
    source_dir: ~str;
    work_dir: ~str;
    filter: option<~str>;
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt(~"source-dir"), reqopt(~"work-dir")];
    let matches = match getopts(args, opts) {
      ok(m) => m,
      err(f) => fail fail_str(f)
    };

    Config {
        source_dir: opt_str(matches, ~"source-dir"),
        work_dir: opt_str(matches, ~"work-dir"),
        filter: if matches.free.is_empty() {
            none
        } else {
            some(matches.free.head())
        }
    }
}

fn test_options(config: Config) -> test_opts {
    {
        filter: config.filter,
        run_ignored: false,
        logfile: none
    }
}

fn find_tests(config: Config) -> ~[test_desc] {
    let html_files = list_dir_path(config.source_dir).filter( |file| file.ends_with(".html") );
    return html_files.map(|file| make_test(config, file) );
}

fn make_test(config: Config, file: ~str) -> test_desc {
    {
        name: file,
        fn: fn~() { run_test(config, file) },
        ignore: false,
        should_fail: false
    }
}

fn run_test(config: Config, file: ~str) {
    let servo_render = render_servo(config, file);
    let ref_render = render_ref(config, file);
    if servo_render != ref_render {
        fail ~"rendered pages to not match";
    }
}

type Render = ~[u8];

const WIDTH: uint = 800;
const HEIGHT: uint = 600;

fn render_servo(config: Config, file: ~str) -> Render {
    let infile = file;
    let outfile = connect(config.work_dir, basename(file) + ".png");
    run_pipeline_png(infile, outfile);
    return sanitize_image(outfile);
}

fn render_ref(config: Config, file: ~str) -> Render {
    let infile = file;
    let outfile = connect(config.work_dir, basename(file) + ".ref.png");
    let rasterize_path = rasterize_path(config);
    let prog = run::start_program("python", ~[rasterize_path, infile, outfile]);
    prog.finish();
    return sanitize_image(outfile);
}

fn sanitize_image(file: ~str) -> Render {
    let buf = io::read_whole_file(file).get();
    let image = servo::image::base::load_from_memory(buf).get();

    // I don't know how to precisely control the rendered height of
    // the Firefox output, so it is larger than we want. Trim it down.
    assert image.width == WIDTH;
    assert image.height >= HEIGHT;
    vec::slice(image.data, 0, image.width * HEIGHT * 4)
}

fn install_rasterize_py(config: Config) {
    import io::WriterUtil;
    let path = rasterize_path(config);
    let writer = io::file_writer(path, ~[io::Create, io::Truncate]).get();
    writer.write_str(rasterize_py());
}

fn rasterize_path(config: Config) -> ~str {
    connect(config.work_dir, ~"rasterize.py")
}

// This is the script that uses phantom.js to render pages
fn rasterize_py() -> ~str { #include_str("rasterize.py") }
<commit_msg>Reuse existing reference images<commit_after>use std;
use servo;

import result::{ok, err};
import std::test::{test_opts, run_tests_console, test_desc};
import std::getopts::{getopts, reqopt, opt_str, fail_str};
import path::{connect, basename};
import os::list_dir_path;
import servo::run_pipeline_png;

fn main(args: ~[~str]) {
    let config = parse_config(args);
    let opts = test_options(config);
    let tests = find_tests(config);
    install_rasterize_py(config);
    run_tests_console(opts, tests);
}

struct Config {
    source_dir: ~str;
    work_dir: ~str;
    filter: option<~str>;
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt(~"source-dir"), reqopt(~"work-dir")];
    let matches = match getopts(args, opts) {
      ok(m) => m,
      err(f) => fail fail_str(f)
    };

    Config {
        source_dir: opt_str(matches, ~"source-dir"),
        work_dir: opt_str(matches, ~"work-dir"),
        filter: if matches.free.is_empty() {
            none
        } else {
            some(matches.free.head())
        }
    }
}

fn test_options(config: Config) -> test_opts {
    {
        filter: config.filter,
        run_ignored: false,
        logfile: none
    }
}

fn find_tests(config: Config) -> ~[test_desc] {
    let html_files = list_dir_path(config.source_dir).filter( |file| file.ends_with(".html") );
    return html_files.map(|file| make_test(config, file) );
}

fn make_test(config: Config, file: ~str) -> test_desc {
    {
        name: file,
        fn: fn~() { run_test(config, file) },
        ignore: false,
        should_fail: false
    }
}

fn run_test(config: Config, file: ~str) {
    let servo_render = render_servo(config, file);
    let ref_render = render_ref(config, file);
    if servo_render != ref_render {
        fail ~"rendered pages do not match";
    }
}

type Render = ~[u8];

const WIDTH: uint = 800;
const HEIGHT: uint = 600;

fn render_servo(config: Config, file: ~str) -> Render {
    let infile = file;
    let outfile = connect(config.work_dir, basename(file) + ".png");
    run_pipeline_png(infile, outfile);
    return sanitize_image(outfile);
}

fn render_ref(config: Config, file: ~str) -> Render {
    let infile = file;
    let outfile = connect(config.work_dir, basename(file) + ".ref.png");
    // After we've generated the reference image once, we don't need
    // to keep launching Firefox
    if !os::path_exists(outfile) {
        let rasterize_path = rasterize_path(config);
        let prog = run::start_program("python", ~[rasterize_path, infile, outfile]);
        prog.finish();
    }
    return sanitize_image(outfile);
}

fn sanitize_image(file: ~str) -> Render {
    let buf = io::read_whole_file(file).get();
    let image = servo::image::base::load_from_memory(buf).get();

    // I don't know how to precisely control the rendered height of
    // the Firefox output, so it is larger than we want. Trim it down.
    assert image.width == WIDTH;
    assert image.height >= HEIGHT;
    vec::slice(image.data, 0, image.width * HEIGHT * 4)
}

fn install_rasterize_py(config: Config) {
    import io::WriterUtil;
    let path = rasterize_path(config);
    let writer = io::file_writer(path, ~[io::Create, io::Truncate]).get();
    writer.write_str(rasterize_py());
}

fn rasterize_path(config: Config) -> ~str {
    connect(config.work_dir, ~"rasterize.py")
}

// This is the script that uses phantom.js to render pages
fn rasterize_py() -> ~str { #include_str("rasterize.py") }
<|endoftext|>


<commit_before>use cbits::leveldb::*;
use libc::{size_t};
use std::slice::*;
use std::vec::raw::*;
use std::vec::*;
use std::iter;
use super::Database;
use super::options::ReadOptions;

pub struct Iterator {
  iter: *mut leveldb_iterator_t,
  start: bool
}

pub trait Iterable {
  fn iter(&self, options: ReadOptions) -> Iterator;
}

impl Iterable for Database {
  fn iter(&self, options: ReadOptions) -> Iterator {
    Iterator::new(self, options)
  }
}

impl Iterator {
  fn new(database: &Database,
         options: ReadOptions) -> Iterator {
    unsafe {
      let iter = leveldb_create_iterator(database.database,
                                         options.options());
      leveldb_iter_seek_to_first(iter);
      Iterator { iter: iter, start: true }
    }
  }

  pub fn valid(&self) -> bool {
    unsafe { leveldb_iter_valid(self.iter) != 0 }
  }

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

  pub fn seek_to_first(self) {
    unsafe { leveldb_iter_seek_to_first(self.iter) }
  }

}

impl Drop for Iterator {
  fn drop(&mut self) {
    unsafe { leveldb_iter_destroy(self.iter) }
  }
}

pub struct Entry {
  iter: *mut leveldb_iterator_t
}

impl Entry {
  pub fn value(self) -> Vec<u8> {
    unsafe {
      let length: size_t = 0;
      let value = leveldb_iter_value(self.iter,
                                     &length) as *const u8;
      from_buf(value, length as uint)
    }
  }

  pub fn key(self) -> Vec<u8> {
    unsafe {
      let length: size_t = 0;
      let value = leveldb_iter_key(self.iter,
                                   &length) as *const u8;
      from_buf(value, length as uint)
    }
  }
}

impl iter::Iterator<Entry> for Iterator {
  fn next(&mut self) -> Option<Entry> {
    unsafe {
      if !self.start() {
        leveldb_iter_next(self.iter);
      } else {
        self.start = false;
      }
      if self.valid() {
        let entry = Entry { iter: self.iter };
        Some(entry)
      } else {
        None
      }
    }
  }
}

<commit_msg>Implement Iterator.last() using the leveldb api<commit_after>use cbits::leveldb::*;
use libc::{size_t};
use std::slice::*;
use std::vec::raw::*;
use std::vec::*;
use std::iter;
use super::Database;
use super::options::ReadOptions;

pub struct Iterator {
  iter: *mut leveldb_iterator_t,
  start: bool
}

pub trait Iterable {
  fn iter(&self, options: ReadOptions) -> Iterator;
}

impl Iterable for Database {
  fn iter(&self, options: ReadOptions) -> Iterator {
    Iterator::new(self, options)
  }
}

impl Iterator {
  fn new(database: &Database,
         options: ReadOptions) -> Iterator {
    unsafe {
      let iter = leveldb_create_iterator(database.database,
                                         options.options());
      leveldb_iter_seek_to_first(iter);
      Iterator { iter: iter, start: true }
    }
  }

  pub fn valid(&self) -> bool {
    unsafe { leveldb_iter_valid(self.iter) != 0 }
  }

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

  pub fn seek_to_first(self) {
    unsafe { leveldb_iter_seek_to_first(self.iter) }
  }

}

impl Drop for Iterator {
  fn drop(&mut self) {
    unsafe { leveldb_iter_destroy(self.iter) }
  }
}

pub struct Entry {
  iter: *mut leveldb_iterator_t
}

impl Entry {
  pub fn value(self) -> Vec<u8> {
    unsafe {
      let length: size_t = 0;
      let value = leveldb_iter_value(self.iter,
                                     &length) as *const u8;
      from_buf(value, length as uint)
    }
  }

  pub fn key(self) -> Vec<u8> {
    unsafe {
      let length: size_t = 0;
      let value = leveldb_iter_key(self.iter,
                                   &length) as *const u8;
      from_buf(value, length as uint)
    }
  }
}

impl iter::Iterator<Entry> for Iterator {
  fn next(&mut self) -> Option<Entry> {
    unsafe {
      if !self.start() {
        leveldb_iter_next(self.iter);
      } else {
        self.start = false;
      }
      if self.valid() {
        let entry = Entry { iter: self.iter };
        Some(entry)
      } else {
        None
      }
    }
  }

  fn last(&mut self) -> Option<Entry> {
    unsafe {
      leveldb_iter_seek_to_last(self.iter);
      Some(Entry { iter: self.iter })
    }
  }
}

<|endoftext|>