<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 http://mozilla.org/MPL/2.0/. */

use cssparser::RGBA;
use dom::attr::{Attr, AttrValue};
use dom::bindings::codegen::Bindings::HTMLFontElementBinding;
use dom::bindings::codegen::Bindings::HTMLFontElementBinding::HTMLFontElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::node::Node;
use dom::virtualmethods::VirtualMethods;
use std::cell::Cell;
use string_cache::Atom;
use style::values::specified;
use util::str::{self, DOMString, parse_legacy_font_size};

#[dom_struct]
pub struct HTMLFontElement {
    htmlelement: HTMLElement,
    color: Cell<Option<RGBA>>,
}

impl HTMLFontElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLFontElement {
        HTMLFontElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
            color: Cell::new(None),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLFontElement> {
        let element = HTMLFontElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLFontElementBinding::Wrap)
    }
}

impl HTMLFontElementMethods for HTMLFontElement {
    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_getter!(Color, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_setter!(SetColor, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_getter!(Face);

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_atomic_setter!(SetFace, "face");

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    make_getter!(Size);

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    fn SetSize(&self, value: DOMString) {
        let element = self.upcast::<Element>();
        let length = parse_length(&value);
        element.set_attribute(&atom!("size"), AttrValue::Length(value, length));
    }
}

impl VirtualMethods for HTMLFontElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match attr.local_name() {
            &atom!(color) => {
                self.color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            _ => {},
        }
    }

    fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
        match name {
            &atom!("face") => AttrValue::from_atomic(value),
            &atom!("size") => {
                let length = parse_length(&value);
                AttrValue::Length(value, length)
            },
            _ => self.super_type().unwrap().parse_plain_attribute(name, value),
        }
    }
}

impl HTMLFontElement {
    pub fn get_color(&self) -> Option<RGBA> {
        self.color.get()
    }

    #[allow(unsafe_code)]
    pub fn get_face(&self) -> Option<Atom> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("face"))
                .map(AttrValue::as_atom)
                .cloned()
        }
    }

    #[allow(unsafe_code)]
    pub fn get_size(&self) -> Option<specified::Length> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("size"))
                .and_then(AttrValue::as_length)
                .cloned()
        }
    }
}

fn parse_length(value: &str) -> Option<specified::Length> {
    parse_legacy_font_size(&value).and_then(|parsed| specified::Length::from_str(&parsed))
}
<commit_msg>Move storage of color attribute on <font>.<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 http://mozilla.org/MPL/2.0/. */

use cssparser::RGBA;
use dom::attr::AttrValue;
use dom::bindings::codegen::Bindings::HTMLFontElementBinding;
use dom::bindings::codegen::Bindings::HTMLFontElementBinding::HTMLFontElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::document::Document;
use dom::element::{Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::node::Node;
use dom::virtualmethods::VirtualMethods;
use string_cache::Atom;
use style::values::specified;
use util::str::{DOMString, parse_legacy_font_size};

#[dom_struct]
pub struct HTMLFontElement {
    htmlelement: HTMLElement,
}

impl HTMLFontElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLFontElement {
        HTMLFontElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLFontElement> {
        let element = HTMLFontElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLFontElementBinding::Wrap)
    }
}

impl HTMLFontElementMethods for HTMLFontElement {
    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_getter!(Color, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_legacy_color_setter!(SetColor, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_getter!(Face);

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_atomic_setter!(SetFace, "face");

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    make_getter!(Size);

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    fn SetSize(&self, value: DOMString) {
        let element = self.upcast::<Element>();
        let length = parse_length(&value);
        element.set_attribute(&atom!("size"), AttrValue::Length(value, length));
    }
}

impl VirtualMethods for HTMLFontElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
        match name {
            &atom!("face") => AttrValue::from_atomic(value),
            &atom!("color") => AttrValue::from_legacy_color(value),
            &atom!("size") => {
                let length = parse_length(&value);
                AttrValue::Length(value, length)
            },
            _ => self.super_type().unwrap().parse_plain_attribute(name, value),
        }
    }
}

impl HTMLFontElement {
    #[allow(unsafe_code)]
    pub fn get_color(&self) -> Option<RGBA> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("color"))
                .and_then(AttrValue::as_color)
                .cloned()
        }
    }

    #[allow(unsafe_code)]
    pub fn get_face(&self) -> Option<Atom> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("face"))
                .map(AttrValue::as_atom)
                .cloned()
        }
    }

    #[allow(unsafe_code)]
    pub fn get_size(&self) -> Option<specified::Length> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("size"))
                .and_then(AttrValue::as_length)
                .cloned()
        }
    }
}

fn parse_length(value: &str) -> Option<specified::Length> {
    parse_legacy_font_size(&value).and_then(|parsed| specified::Length::from_str(&parsed))
}
<|endoftext|>


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

use crate::{
    json_rpc::JsonRpcClientWrapper,
    validator_set::{validator_set_full_node_addresses, validator_set_validator_addresses},
};
use diem_config::{
    config::{RoleType, HANDSHAKE_VERSION},
    network_id::{NetworkContext, NetworkId},
};
use diem_crypto::{x25519, x25519::PRIVATE_KEY_SIZE};
use diem_management::error::Error;
use diem_network_address_encryption::Encryptor;
use diem_secure_storage::{InMemoryStorage, Storage};
use diem_types::{
    account_address,
    chain_id::ChainId,
    network_address::{
        encrypted::{Key, KeyVersion, KEY_LEN},
        NetworkAddress,
    },
    PeerId,
};
use fallible::copy_from_slice::copy_slice_to_vec;
use netcore::transport::tcp::{resolve_and_connect, TcpSocket};
use network::{
    noise::{HandshakeAuthMode, NoiseUpgrader},
    protocols::wire::handshake::v1::SupportedProtocols,
    transport::{upgrade_outbound, UpgradeContext, SUPPORTED_MESSAGING_PROTOCOL},
    ProtocolId,
};
use std::{collections::BTreeMap, sync::Arc};
use structopt::StructOpt;
use tokio::{runtime::Runtime, time::Duration};

const DEFAULT_TIMEOUT_SECONDS: u64 = 5;

#[derive(Debug, StructOpt)]
pub struct CheckEndpoint {
    /// `NetworkAddress` of remote server interface
    #[structopt(long)]
    address: NetworkAddress,
    /// `ChainId` of remote server
    #[structopt(long)]
    chain_id: ChainId,
    /// `NetworkId` of remote server interface
    #[structopt(long)]
    network_id: NetworkId,
    /// `PrivateKey` to connect to remote server
    #[structopt(long, parse(try_from_str = parse_private_key_hex))]
    private_key: Option<x25519::PrivateKey>,
    /// Optional number of seconds to timeout attempting to connect to endpoint
    #[structopt(long)]
    timeout_seconds: Option<u64>,
}

fn parse_private_key_hex(src: &str) -> Result<x25519::PrivateKey, Error> {
    let input = src.trim();
    if input.len() != 64 {
        return Err(Error::CommandArgumentError(
            "Invalid private key length, must be 64 hex characters".to_string(),
        ));
    }

    let value_slice = hex::decode(src.trim())
        .map_err(|_| Error::CommandArgumentError(format!("Not a valid private key: {}", src)))?;

    let mut value = [0; PRIVATE_KEY_SIZE];
    copy_slice_to_vec(&value_slice, &mut value)
        .map_err(|e| Error::CommandArgumentError(format!("{}", e)))?;

    Ok(x25519::PrivateKey::from(value))
}

impl CheckEndpoint {
    pub fn execute(self) -> Result<String, Error> {
        validate_address(&self.address)?;
        let private_key = self.private_key.unwrap_or_else(|| {
            let dummy = [0; PRIVATE_KEY_SIZE];
            x25519::PrivateKey::from(dummy)
        });
        let (peer_id, public_key) = private_key_to_public_info(&private_key);
        let timeout = timeout_duration(self.timeout_seconds);
        println!(
            "Connecting with peer_id {} and pubkey {} to {} with timeout: {:?}",
            peer_id, public_key, self.address, timeout
        );
        check_endpoint(
            build_upgrade_context(self.chain_id, self.network_id, peer_id, private_key),
            self.address,
            timeout,
        )
    }
}

#[derive(Debug, StructOpt)]
pub struct CheckValidatorSetEndpoints {
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: String,
    /// Specifies whether or not to evaluate validators or fullnodes
    #[structopt(long)]
    role: RoleType,
    /// The expected on-chain key, only required for validator checks
    #[structopt(long, required_if("role", "validator"), parse(try_from_str = parse_validator_key_hex))]
    address_encryption_key: Option<Key>,
    /// The expected on-chain key version, only required for validator checks
    #[structopt(long, required_if("role", "validator"))]
    version: Option<KeyVersion>,
    /// `ChainId` of remote server
    #[structopt(long)]
    chain_id: ChainId,
    /// Private key to connect to remote server
    #[structopt(long, parse(try_from_str = parse_private_key_hex))]
    private_key: Option<x25519::PrivateKey>,
    /// Optional number of seconds to timeout attempting to connect to endpoint
    #[structopt(long)]
    timeout_seconds: Option<u64>,
}

fn parse_validator_key_hex(src: &str) -> Result<Key, Error> {
    let potential_err_msg = format!("Not a valid encryption key: {}", src);
    let value_slice =
        hex::decode(src.trim()).map_err(|_| Error::CommandArgumentError(potential_err_msg))?;

    let mut value = [0; KEY_LEN];
    copy_slice_to_vec(&value_slice, &mut value)
        .map_err(|e| Error::CommandArgumentError(format!("{}", e)))?;
    Ok(value)
}

impl CheckValidatorSetEndpoints {
    pub fn execute(self) -> Result<String, Error> {
        let is_validator = self.role.is_validator();
        let client = JsonRpcClientWrapper::new(self.json_server);
        let private_key = if let Some(private_key) = self.private_key {
            private_key
        } else if is_validator {
            return Err(Error::CommandArgumentError(
                "Must provide a private key for validators".into(),
            ));
        } else {
            let dummy = [0; PRIVATE_KEY_SIZE];
            x25519::PrivateKey::from(dummy)
        };

        let nodes = if is_validator {
            let address_encryption_key = self.address_encryption_key.ok_or_else(|| {
                Error::CommandArgumentError(
                    "Must provide address encryption key for validators".into(),
                )
            })?;
            let version = self.version.ok_or_else(|| {
                Error::CommandArgumentError("Must provide version for validators".into())
            })?;

            // Following unwraps shouldn't fail as it is in memory
            let mut encryptor = Encryptor::new(Storage::InMemoryStorage(InMemoryStorage::new()));
            encryptor.initialize().unwrap();
            encryptor.add_key(version, address_encryption_key).unwrap();
            encryptor.set_current_version(version).unwrap();

            validator_set_validator_addresses(client, &encryptor, None)?
        } else {
            validator_set_full_node_addresses(client, None)?
        };

        // Build a single upgrade context to run all the checks
        let network_id = if is_validator {
            NetworkId::Validator
        } else {
            NetworkId::Public
        };

        let (peer_id, public_key) = private_key_to_public_info(&private_key);
        let upgrade_context =
            build_upgrade_context(self.chain_id, network_id, peer_id, private_key);

        let timeout = timeout_duration(self.timeout_seconds);
        println!(
            "Checking nodes with peer_id {} and public_key {}, timeout {:?}",
            peer_id, public_key, timeout
        );

        // Check all the addresses accordingly
        for (name, peer_id, addrs) in nodes {
            for addr in addrs {
                match check_endpoint(upgrade_context.clone(), addr, timeout) {
                    Ok(_) => println!("{} -- good", name),
                    Err(err) => println!("{} : {} -- bad -- {}", name, peer_id, err),
                };
            }
        }

        Ok("Complete!".to_string())
    }
}

/// Builds a listener free noise connector
fn build_upgrade_context(
    chain_id: ChainId,
    network_id: NetworkId,
    peer_id: PeerId,
    private_key: x25519::PrivateKey,
) -> Arc<UpgradeContext> {
    // RoleType doesn't matter, but the `NetworkId` and `PeerId` are used in handshakes
    let network_context = Arc::new(NetworkContext::new(
        RoleType::FullNode,
        network_id.clone(),
        peer_id,
    ));

    // Let's make sure some protocol can be connected.  In the future we may want to allow for specifics
    let mut supported_protocols = BTreeMap::new();
    supported_protocols.insert(
        SUPPORTED_MESSAGING_PROTOCOL,
        SupportedProtocols::from(ProtocolId::all().iter()),
    );

    // Build the noise and network handshake, without running a full Noise server with listener
    Arc::new(UpgradeContext::new(
        NoiseUpgrader::new(
            network_context,
            private_key,
            // If we had an incoming message, auth mode would matter
            HandshakeAuthMode::server_only(),
        ),
        HANDSHAKE_VERSION,
        supported_protocols,
        chain_id,
        network_id,
    ))
}

fn timeout_duration(maybe_secs: Option<u64>) -> Duration {
    Duration::from_secs(if let Some(secs) = maybe_secs {
        secs
    } else {
        DEFAULT_TIMEOUT_SECONDS
    })
}

fn validate_address(address: &NetworkAddress) -> Result<(), Error> {
    if !address.is_diemnet_addr() {
        Err(Error::CommandArgumentError(
            "Address must have ip, tcp, noise key, and handshake".to_string(),
        ))
    } else {
        Ok(())
    }
}

/// Wrapper for `check_endpoint_inner` to handle runtime
fn check_endpoint(
    upgrade_context: Arc<UpgradeContext>,
    address: NetworkAddress,
    timeout: Duration,
) -> Result<String, Error> {
    let runtime = Runtime::new().unwrap();
    let remote_pubkey = address.find_noise_proto().unwrap();

    let connect_future = async {
        tokio::time::timeout(
            timeout,
            check_endpoint_inner(upgrade_context, address.clone(), remote_pubkey),
        )
        .await
        .map_err(|_| Error::Timeout("CheckEndpoint", address.to_string()))
    };

    runtime.block_on(connect_future)?
}

/// Connects via Noise, and then drops the connection
async fn check_endpoint_inner(
    upgrade_context: Arc<UpgradeContext>,
    address: NetworkAddress,
    remote_pubkey: x25519::PublicKey,
) -> Result<String, Error> {
    // Connect to the address, this should handle DNS resolution
    let fut_socket = async {
        resolve_and_connect(address.clone())
            .await
            .map(TcpSocket::new)
    };

    // The peer id doesn't matter because we don't validate it
    let remote_peer_id = account_address::from_identity_public_key(remote_pubkey);
    match upgrade_outbound(
        upgrade_context,
        fut_socket,
        address.clone(),
        remote_peer_id,
        remote_pubkey,
    )
    .await
    {
        Ok(conn) => {
            let msg = format!("Successfully connected to {}", conn.metadata.addr);

            // Disconnect
            drop(conn);
            Ok(msg)
        }
        Err(error) => Err(Error::UnexpectedError(format!(
            "Failed to connect to {} due to {}",
            address, error
        ))),
    }
}

/// Derive the peer id that we're using.  This is a convenience to only have to provide private key
fn private_key_to_public_info(private_key: &x25519::PrivateKey) -> (PeerId, x25519::PublicKey) {
    let public_key = private_key.public_key();
    let peer_id = account_address::from_identity_public_key(public_key);
    (peer_id, public_key)
}
<commit_msg>[operational-tool] Allow network checker to skip noise handshake<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    json_rpc::JsonRpcClientWrapper,
    validator_set::{validator_set_full_node_addresses, validator_set_validator_addresses},
};
use diem_config::{
    config::{RoleType, HANDSHAKE_VERSION},
    network_id::{NetworkContext, NetworkId},
};
use diem_crypto::{x25519, x25519::PRIVATE_KEY_SIZE};
use diem_management::error::Error;
use diem_network_address_encryption::Encryptor;
use diem_secure_storage::{InMemoryStorage, Storage};
use diem_types::{
    account_address,
    chain_id::ChainId,
    network_address::{
        encrypted::{Key, KeyVersion, KEY_LEN},
        NetworkAddress,
    },
    PeerId,
};
use fallible::copy_from_slice::copy_slice_to_vec;
use futures::{AsyncReadExt, AsyncWriteExt};
use netcore::transport::tcp::{resolve_and_connect, TcpSocket};
use network::{
    noise::{HandshakeAuthMode, NoiseUpgrader},
    protocols::wire::handshake::v1::SupportedProtocols,
    transport::{upgrade_outbound, UpgradeContext, SUPPORTED_MESSAGING_PROTOCOL},
    ProtocolId,
};
use std::{collections::BTreeMap, sync::Arc};
use structopt::StructOpt;
use tokio::{runtime::Runtime, time::Duration};

const DEFAULT_TIMEOUT_SECONDS: u64 = 5;

#[derive(Debug, StructOpt)]
pub struct CheckEndpoint {
    /// `NetworkAddress` of remote server interface
    #[structopt(long)]
    address: NetworkAddress,
    /// `ChainId` of remote server
    #[structopt(long)]
    chain_id: ChainId,
    /// `NetworkId` of remote server interface
    #[structopt(long)]
    network_id: NetworkId,
    /// `PrivateKey` to connect to remote server
    #[structopt(long, parse(try_from_str = parse_private_key_hex))]
    private_key: Option<x25519::PrivateKey>,
    /// Optional number of seconds to timeout attempting to connect to endpoint
    #[structopt(long)]
    timeout_seconds: Option<u64>,
    /// Skip handshake for network checking
    #[structopt(long)]
    no_handshake: bool,
}

fn parse_private_key_hex(src: &str) -> Result<x25519::PrivateKey, Error> {
    let input = src.trim();
    if input.len() != 64 {
        return Err(Error::CommandArgumentError(
            "Invalid private key length, must be 64 hex characters".to_string(),
        ));
    }

    let value_slice = hex::decode(src.trim())
        .map_err(|_| Error::CommandArgumentError(format!("Not a valid private key: {}", src)))?;

    let mut value = [0; PRIVATE_KEY_SIZE];
    copy_slice_to_vec(&value_slice, &mut value)
        .map_err(|e| Error::CommandArgumentError(format!("{}", e)))?;

    Ok(x25519::PrivateKey::from(value))
}

impl CheckEndpoint {
    pub fn execute(self) -> Result<String, Error> {
        validate_address(&self.address)?;
        let private_key = self.private_key.unwrap_or_else(|| {
            let dummy = [0; PRIVATE_KEY_SIZE];
            x25519::PrivateKey::from(dummy)
        });
        let (peer_id, public_key) = private_key_to_public_info(&private_key);
        let timeout = timeout_duration(self.timeout_seconds);
        println!(
            "Connecting with peer_id {} and pubkey {} to {} with timeout: {:?}",
            peer_id, public_key, self.address, timeout
        );
        check_endpoint(
            build_upgrade_context(self.chain_id, self.network_id, peer_id, private_key),
            self.address,
            timeout,
            self.no_handshake,
        )
    }
}

#[derive(Debug, StructOpt)]
pub struct CheckValidatorSetEndpoints {
    /// JSON-RPC Endpoint (e.g. http://localhost:8080)
    #[structopt(long, required_unless = "config")]
    json_server: String,
    /// Specifies whether or not to evaluate validators or fullnodes
    #[structopt(long)]
    role: RoleType,
    /// The expected on-chain key, only required for validator checks
    #[structopt(long, required_if("role", "validator"), parse(try_from_str = parse_validator_key_hex))]
    address_encryption_key: Option<Key>,
    /// The expected on-chain key version, only required for validator checks
    #[structopt(long, required_if("role", "validator"))]
    version: Option<KeyVersion>,
    /// `ChainId` of remote server
    #[structopt(long)]
    chain_id: ChainId,
    /// Private key to connect to remote server
    #[structopt(long, parse(try_from_str = parse_private_key_hex))]
    private_key: Option<x25519::PrivateKey>,
    /// Optional number of seconds to timeout attempting to connect to endpoint
    #[structopt(long)]
    timeout_seconds: Option<u64>,
    /// Skip handshake for network checking
    #[structopt(long)]
    no_handshake: bool,
}

fn parse_validator_key_hex(src: &str) -> Result<Key, Error> {
    let potential_err_msg = format!("Not a valid encryption key: {}", src);
    let value_slice =
        hex::decode(src.trim()).map_err(|_| Error::CommandArgumentError(potential_err_msg))?;

    let mut value = [0; KEY_LEN];
    copy_slice_to_vec(&value_slice, &mut value)
        .map_err(|e| Error::CommandArgumentError(format!("{}", e)))?;
    Ok(value)
}

impl CheckValidatorSetEndpoints {
    pub fn execute(self) -> Result<String, Error> {
        let is_validator = self.role.is_validator();
        let client = JsonRpcClientWrapper::new(self.json_server);
        let private_key = if let Some(private_key) = self.private_key {
            private_key
        } else if is_validator && !self.no_handshake {
            return Err(Error::CommandArgumentError(
                "Must provide a private key for validators".into(),
            ));
        } else {
            let dummy = [0; PRIVATE_KEY_SIZE];
            x25519::PrivateKey::from(dummy)
        };

        let nodes = if is_validator {
            let address_encryption_key = self.address_encryption_key.ok_or_else(|| {
                Error::CommandArgumentError(
                    "Must provide address encryption key for validators".into(),
                )
            })?;
            let version = self.version.ok_or_else(|| {
                Error::CommandArgumentError("Must provide version for validators".into())
            })?;

            // Following unwraps shouldn't fail as it is in memory
            let mut encryptor = Encryptor::new(Storage::InMemoryStorage(InMemoryStorage::new()));
            encryptor.initialize().unwrap();
            encryptor.add_key(version, address_encryption_key).unwrap();
            encryptor.set_current_version(version).unwrap();

            validator_set_validator_addresses(client, &encryptor, None)?
        } else {
            validator_set_full_node_addresses(client, None)?
        };

        // Build a single upgrade context to run all the checks
        let network_id = if is_validator {
            NetworkId::Validator
        } else {
            NetworkId::Public
        };

        let (peer_id, public_key) = private_key_to_public_info(&private_key);
        let upgrade_context =
            build_upgrade_context(self.chain_id, network_id, peer_id, private_key);

        let timeout = timeout_duration(self.timeout_seconds);
        println!(
            "Checking nodes with peer_id {} and public_key {}, timeout {:?}",
            peer_id, public_key, timeout
        );

        // Check all the addresses accordingly
        for (name, peer_id, addrs) in nodes {
            for addr in addrs {
                match check_endpoint(upgrade_context.clone(), addr, timeout, self.no_handshake) {
                    Ok(_) => println!("{} -- good", name),
                    Err(err) => println!("{} : {} -- bad -- {}", name, peer_id, err),
                };
            }
        }

        Ok("Complete!".to_string())
    }
}

/// Builds a listener free noise connector
fn build_upgrade_context(
    chain_id: ChainId,
    network_id: NetworkId,
    peer_id: PeerId,
    private_key: x25519::PrivateKey,
) -> Arc<UpgradeContext> {
    // RoleType doesn't matter, but the `NetworkId` and `PeerId` are used in handshakes
    let network_context = Arc::new(NetworkContext::new(
        RoleType::FullNode,
        network_id.clone(),
        peer_id,
    ));

    // Let's make sure some protocol can be connected.  In the future we may want to allow for specifics
    let mut supported_protocols = BTreeMap::new();
    supported_protocols.insert(
        SUPPORTED_MESSAGING_PROTOCOL,
        SupportedProtocols::from(ProtocolId::all().iter()),
    );

    // Build the noise and network handshake, without running a full Noise server with listener
    Arc::new(UpgradeContext::new(
        NoiseUpgrader::new(
            network_context,
            private_key,
            // If we had an incoming message, auth mode would matter
            HandshakeAuthMode::server_only(),
        ),
        HANDSHAKE_VERSION,
        supported_protocols,
        chain_id,
        network_id,
    ))
}

fn timeout_duration(maybe_secs: Option<u64>) -> Duration {
    Duration::from_secs(if let Some(secs) = maybe_secs {
        secs
    } else {
        DEFAULT_TIMEOUT_SECONDS
    })
}

fn validate_address(address: &NetworkAddress) -> Result<(), Error> {
    if !address.is_diemnet_addr() {
        Err(Error::CommandArgumentError(
            "Address must have ip, tcp, noise key, and handshake".to_string(),
        ))
    } else {
        Ok(())
    }
}

/// Wrapper for `check_endpoint_inner` to handle runtime
fn check_endpoint(
    upgrade_context: Arc<UpgradeContext>,
    address: NetworkAddress,
    timeout: Duration,
    no_handshake: bool,
) -> Result<String, Error> {
    let runtime = Runtime::new().unwrap();
    let remote_pubkey = address.find_noise_proto().unwrap();

    let connect_future = async {
        tokio::time::timeout(timeout, async {
            if no_handshake {
                check_endpoint_inner_no_handshake(address.clone()).await
            } else {
                check_endpoint_inner(upgrade_context.clone(), address.clone(), remote_pubkey).await
            }
        })
        .await
        .map_err(|_| Error::Timeout("CheckEndpoint", address.to_string()))
    };

    runtime.block_on(connect_future)?
}

/// Connects via Noise, and then drops the connection
async fn check_endpoint_inner(
    upgrade_context: Arc<UpgradeContext>,
    address: NetworkAddress,
    remote_pubkey: x25519::PublicKey,
) -> Result<String, Error> {
    // Connect to the address, this should handle DNS resolution
    let fut_socket = async {
        resolve_and_connect(address.clone())
            .await
            .map(TcpSocket::new)
    };

    // The peer id doesn't matter because we don't validate it
    let remote_peer_id = account_address::from_identity_public_key(remote_pubkey);
    match upgrade_outbound(
        upgrade_context,
        fut_socket,
        address.clone(),
        remote_peer_id,
        remote_pubkey,
    )
    .await
    {
        Ok(conn) => {
            let msg = format!("Successfully connected to {}", conn.metadata.addr);

            // Disconnect
            drop(conn);
            Ok(msg)
        }
        Err(error) => Err(Error::UnexpectedError(format!(
            "Failed to connect to {} due to {}",
            address, error
        ))),
    }
}

const INVALID_NOISE_HEADER: &[u8; 152] = &[7; 152];

async fn check_endpoint_inner_no_handshake(address: NetworkAddress) -> Result<String, Error> {
    let mut socket = resolve_and_connect(address.clone())
        .await
        .map(TcpSocket::new)
        .map_err(|error| {
            Error::UnexpectedError(format!("Failed to connect to {} due to {}", address, error))
        })?;

    if let Err(error) = socket.write_all(INVALID_NOISE_HEADER).await {
        return Err(Error::UnexpectedError(format!(
            "Failed to write to {} due to {}",
            address, error
        )));
    }

    let buf = &mut [0; 1];
    match socket.read(buf).await {
        Ok(size) => {
            // We should be able to write to the socket dummy data

            if size == 0 {
                // Connection is open, and doesn't return anything
                // This is the closest we can get to working
                return Ok(format!(
                    "Accepted write and responded with nothing at {}",
                    address
                ));
            } else {
                Err(Error::UnexpectedError(format!(
                    "Endpoint {} responded with data when it shouldn't",
                    address
                )))
            }
        }
        Err(error) => Err(Error::UnexpectedError(format!(
            "Failed to read from {} due to {}",
            address, error
        ))),
    }
}

/// Derive the peer id that we're using.  This is a convenience to only have to provide private key
fn private_key_to_public_info(private_key: &x25519::PrivateKey) -> (PeerId, x25519::PublicKey) {
    let public_key = private_key.public_key();
    let peer_id = account_address::from_identity_public_key(public_key);
    (peer_id, public_key)
}
<|endoftext|>


<commit_before><commit_msg>Added simple info reporting example.<commit_after><|endoftext|>


<commit_before><commit_msg>apply the context combinator at the right index<commit_after><|endoftext|>


<commit_before><commit_msg>Add an example that renders a lot of tabs<commit_after><|endoftext|>


<commit_before><commit_msg>Don't break out of scheduler after a `WAIT`<commit_after><|endoftext|>


<commit_before><commit_msg>Rename primary_header parser to header parser<commit_after><|endoftext|>


<commit_before><commit_msg>rename RPN test func + use single expression parsing + useless use statement<commit_after><|endoftext|>


<commit_before>//! Types for extensible text message events ([MSC1767]).
//!
//! # Extensible events
//!
//! MSCs [1767] (Text, Emote and Notice), [3551] (Files), [3552] (Images and Stickers), [3553]
//! (Videos), [3246] (Audio), and [3488] (Location) introduce new primary types called extensible
//! events. These types are meant to replace the `m.room.message` primary type and its `msgtype`s.
//! Other MSCs introduce new types with an `m.room.message` fallback, like [MSC3245] (Voice
//! Messages), and types that only have an extensible events format, like [MSC3381] (Polls).
//!
//! # Transition Period
//!
//! MSC1767 defines a transition period that will start after the extensible events are released in
//! a Matrix version. It should last approximately one year, but the end of that period will be
//! formalized in a new Matrix version.
//!
//! The new primary types should not be sent over the Matrix network before the end of the
//! transition period. Instead, transitional `m.room.message` events should be sent. These
//! transitional events include the content of the now legacy `m.room.message` event and the content
//! of the new extensible event types in a single event.
//!
//! # How to use them
//!
//! First, you can enable the `unstable-extensible-events` feature from the `ruma` crate, that
//! will enable all the MSCs for the extensible events that correspond to the legacy `msgtype`s
//! (1767, 3246, 3488, 3551, 3552, 3553). It is also possible to enable only the MSCs you want with
//! the `unstable-mscXXXX` features (where `XXXX` is the number of the MSC).
//!
//! The recommended way to send transitional extensible events while they are unstable and during
//! the transition period is to build one of the new primary types and then to convert it to a
//! [`RoomMessageEventContent`] by using `.into()` or `RoomMessageEventContent::from()`. The
//! provided constructors will copy the relevant data in the legacy fields.
//!
//! For incoming events, a `RoomMessageEventContent` can be converted to an extensible event with
//! the relevant `from_*_room_message` method on the primary type. This conversion will work even
//! with legacy `m.room.message` events that don't have extensible events content.
//!
//! It is also possible to enable extensible events support and continue using
//! `RoomMessageEventContent`'s constructors. The data will be duplicated in both the legacy and
//! extensible events fields.
//!
//! [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [3551]: https://github.com/matrix-org/matrix-spec-proposals/pull/3551
//! [3552]: https://github.com/matrix-org/matrix-spec-proposals/pull/3552
//! [3553]: https://github.com/matrix-org/matrix-spec-proposals/pull/3553
//! [3246]: https://github.com/matrix-org/matrix-spec-proposals/pull/3246
//! [3488]: https://github.com/matrix-org/matrix-spec-proposals/pull/3488
//! [MSC3245]: https://github.com/matrix-org/matrix-spec-proposals/pull/3245
//! [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
//! [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
use std::{convert::TryFrom, ops::Deref};

use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};
use thiserror::Error;

pub(crate) mod content_serde;

use content_serde::MessageContentSerDeHelper;

use super::room::message::{FormattedBody, MessageFormat, Relation, TextMessageEventContent};

/// The payload for an extensible text message.
///
/// This is the new primary type introduced in [MSC1767] and should not be sent before the end of
/// the transition period. See the documentation of the [`message`] module for more information.
///
/// `MessageEventContent` can be converted to a [`RoomMessageEventContent`] with a
/// [`MessageType::Text`]. You can convert it back with
/// [`MessageEventContent::from_text_room_message()`].
///
/// [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
/// [`message`]: super::message
/// [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
/// [`MessageType::Text`]: super::room::message::MessageType::Text
#[derive(Clone, Debug, Serialize, Deserialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.message", kind = MessageLike)]
pub struct MessageEventContent {
    /// The message's text content.
    #[serde(flatten)]
    pub message: MessageContent,

    /// Information about related messages for [rich replies].
    ///
    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
    #[serde(flatten, skip_serializing_if = "Option::is_none")]
    pub relates_to: Option<Relation>,
}

impl MessageEventContent {
    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self { message: MessageContent::plain(body), relates_to: None }
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self { message: MessageContent::html(body, html_body), relates_to: None }
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        Self { message: MessageContent::markdown(body), relates_to: None }
    }

    /// Create a new `MessageEventContent` from the given `TextMessageEventContent` and optional
    /// relation.
    pub fn from_text_room_message(
        content: TextMessageEventContent,
        relates_to: Option<Relation>,
    ) -> Self {
        let TextMessageEventContent { body, formatted, message, .. } = content;
        if let Some(message) = message {
            Self { message, relates_to }
        } else {
            Self { message: MessageContent::from_room_message_content(body, formatted), relates_to }
        }
    }
}

/// Text message content.
///
/// A `MessageContent` must contain at least one message to be used as a fallback text
/// representation.
#[derive(Clone, Debug, Deserialize)]
#[serde(try_from = "MessageContentSerDeHelper")]
pub struct MessageContent(pub(crate) Vec<Text>);

impl MessageContent {
    /// Create a `MessageContent` from an array of messages.
    ///
    /// Returns `None` if the array is empty.
    pub fn new(messages: Vec<Text>) -> Option<Self> {
        if messages.is_empty() {
            None
        } else {
            Some(Self(messages))
        }
    }

    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self(vec![Text::plain(body)])
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self(vec![Text::html(html_body), Text::plain(body)])
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        let mut message = Vec::with_capacity(2);
        if let Some(html_body) = Text::markdown(&body) {
            message.push(html_body);
        }
        message.push(Text::plain(body));
        Self(message)
    }

    /// Create a new `MessageContent` from the given body and optional formatted body.
    pub fn from_room_message_content(body: String, formatted: Option<FormattedBody>) -> Self {
        if let Some(FormattedBody { body: html_body, .. }) =
            formatted.filter(|formatted| formatted.format == MessageFormat::Html)
        {
            Self::html(body, html_body)
        } else {
            Self::plain(body)
        }
    }

    /// Get the plain text representation of this message.
    pub fn find_plain(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/plain")
            .map(|content| content.body.as_ref())
    }

    /// Get the HTML representation of this message.
    pub fn find_html(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/html")
            .map(|content| content.body.as_ref())
    }
}

/// The error type returned when trying to construct an empty `MessageContent`.
#[derive(Debug, Error)]
#[non_exhaustive]
#[error("MessageContent cannot be empty")]
pub struct EmptyMessageContentError;

impl TryFrom<Vec<Text>> for MessageContent {
    type Error = EmptyMessageContentError;

    fn try_from(messages: Vec<Text>) -> Result<Self, Self::Error> {
        Self::new(messages).ok_or(EmptyMessageContentError)
    }
}

impl Deref for MessageContent {
    type Target = [Text];

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

/// Text message content.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Text {
    /// The mime type of the `body`.
    #[serde(default = "Text::default_mimetype")]
    pub mimetype: String,

    /// The text content.
    pub body: String,

    /// The language of the text.
    ///
    /// This must be a valid language code according to [BCP 47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt).
    #[cfg(feature = "unstable-msc3554")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub lang: Option<String>,
}

impl Text {
    /// Creates a new plain text message body.
    pub fn plain(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/plain".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body.
    pub fn html(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/html".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body by parsing the Markdown in `body`.
    ///
    /// Returns `None` if no Markdown formatting was found.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str>) -> Option<Self> {
        let body = body.as_ref();
        let mut html_body = String::new();

        pulldown_cmark::html::push_html(&mut html_body, pulldown_cmark::Parser::new(body));

        (html_body != format!("<p>{}</p>\n", body)).then(|| Self::html(html_body))
    }

    fn default_mimetype() -> String {
        "text/plain".to_owned()
    }
}

/// The error type returned when a conversion to an extensible event type fails.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum TryFromExtensibleError {
    /// A field is missing.
    #[error("missing field `{0}`")]
    MissingField(String),
}
<commit_msg>events: Add a link to MSC3554<commit_after>//! Types for extensible text message events ([MSC1767]).
//!
//! # Extensible events
//!
//! MSCs [1767] (Text, Emote and Notice), [3551] (Files), [3552] (Images and Stickers), [3553]
//! (Videos), [3246] (Audio), and [3488] (Location) introduce new primary types called extensible
//! events. These types are meant to replace the `m.room.message` primary type and its `msgtype`s.
//! Other MSCs introduce new types with an `m.room.message` fallback, like [MSC3245] (Voice
//! Messages), and types that only have an extensible events format, like [MSC3381] (Polls).
//!
//! # Transition Period
//!
//! MSC1767 defines a transition period that will start after the extensible events are released in
//! a Matrix version. It should last approximately one year, but the end of that period will be
//! formalized in a new Matrix version.
//!
//! The new primary types should not be sent over the Matrix network before the end of the
//! transition period. Instead, transitional `m.room.message` events should be sent. These
//! transitional events include the content of the now legacy `m.room.message` event and the content
//! of the new extensible event types in a single event.
//!
//! # How to use them
//!
//! First, you can enable the `unstable-extensible-events` feature from the `ruma` crate, that
//! will enable all the MSCs for the extensible events that correspond to the legacy `msgtype`s
//! (1767, 3246, 3488, 3551, 3552, 3553). It is also possible to enable only the MSCs you want with
//! the `unstable-mscXXXX` features (where `XXXX` is the number of the MSC).
//!
//! The recommended way to send transitional extensible events while they are unstable and during
//! the transition period is to build one of the new primary types and then to convert it to a
//! [`RoomMessageEventContent`] by using `.into()` or `RoomMessageEventContent::from()`. The
//! provided constructors will copy the relevant data in the legacy fields.
//!
//! For incoming events, a `RoomMessageEventContent` can be converted to an extensible event with
//! the relevant `from_*_room_message` method on the primary type. This conversion will work even
//! with legacy `m.room.message` events that don't have extensible events content.
//!
//! It is also possible to enable extensible events support and continue using
//! `RoomMessageEventContent`'s constructors. The data will be duplicated in both the legacy and
//! extensible events fields.
//!
//! [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
//! [3551]: https://github.com/matrix-org/matrix-spec-proposals/pull/3551
//! [3552]: https://github.com/matrix-org/matrix-spec-proposals/pull/3552
//! [3553]: https://github.com/matrix-org/matrix-spec-proposals/pull/3553
//! [3246]: https://github.com/matrix-org/matrix-spec-proposals/pull/3246
//! [3488]: https://github.com/matrix-org/matrix-spec-proposals/pull/3488
//! [MSC3245]: https://github.com/matrix-org/matrix-spec-proposals/pull/3245
//! [MSC3381]: https://github.com/matrix-org/matrix-spec-proposals/pull/3381
//! [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
use std::{convert::TryFrom, ops::Deref};

use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};
use thiserror::Error;

pub(crate) mod content_serde;

use content_serde::MessageContentSerDeHelper;

use super::room::message::{FormattedBody, MessageFormat, Relation, TextMessageEventContent};

/// The payload for an extensible text message.
///
/// This is the new primary type introduced in [MSC1767] and should not be sent before the end of
/// the transition period. See the documentation of the [`message`] module for more information.
///
/// `MessageEventContent` can be converted to a [`RoomMessageEventContent`] with a
/// [`MessageType::Text`]. You can convert it back with
/// [`MessageEventContent::from_text_room_message()`].
///
/// [MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
/// [`message`]: super::message
/// [`RoomMessageEventContent`]: super::room::message::RoomMessageEventContent
/// [`MessageType::Text`]: super::room::message::MessageType::Text
#[derive(Clone, Debug, Serialize, Deserialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.message", kind = MessageLike)]
pub struct MessageEventContent {
    /// The message's text content.
    #[serde(flatten)]
    pub message: MessageContent,

    /// Information about related messages for [rich replies].
    ///
    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
    #[serde(flatten, skip_serializing_if = "Option::is_none")]
    pub relates_to: Option<Relation>,
}

impl MessageEventContent {
    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self { message: MessageContent::plain(body), relates_to: None }
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self { message: MessageContent::html(body, html_body), relates_to: None }
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        Self { message: MessageContent::markdown(body), relates_to: None }
    }

    /// Create a new `MessageEventContent` from the given `TextMessageEventContent` and optional
    /// relation.
    pub fn from_text_room_message(
        content: TextMessageEventContent,
        relates_to: Option<Relation>,
    ) -> Self {
        let TextMessageEventContent { body, formatted, message, .. } = content;
        if let Some(message) = message {
            Self { message, relates_to }
        } else {
            Self { message: MessageContent::from_room_message_content(body, formatted), relates_to }
        }
    }
}

/// Text message content.
///
/// A `MessageContent` must contain at least one message to be used as a fallback text
/// representation.
#[derive(Clone, Debug, Deserialize)]
#[serde(try_from = "MessageContentSerDeHelper")]
pub struct MessageContent(pub(crate) Vec<Text>);

impl MessageContent {
    /// Create a `MessageContent` from an array of messages.
    ///
    /// Returns `None` if the array is empty.
    pub fn new(messages: Vec<Text>) -> Option<Self> {
        if messages.is_empty() {
            None
        } else {
            Some(Self(messages))
        }
    }

    /// A convenience constructor to create a plain text message.
    pub fn plain(body: impl Into<String>) -> Self {
        Self(vec![Text::plain(body)])
    }

    /// A convenience constructor to create an HTML message.
    pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
        Self(vec![Text::html(html_body), Text::plain(body)])
    }

    /// A convenience constructor to create a Markdown message.
    ///
    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
    /// text message.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
        let mut message = Vec::with_capacity(2);
        if let Some(html_body) = Text::markdown(&body) {
            message.push(html_body);
        }
        message.push(Text::plain(body));
        Self(message)
    }

    /// Create a new `MessageContent` from the given body and optional formatted body.
    pub fn from_room_message_content(body: String, formatted: Option<FormattedBody>) -> Self {
        if let Some(FormattedBody { body: html_body, .. }) =
            formatted.filter(|formatted| formatted.format == MessageFormat::Html)
        {
            Self::html(body, html_body)
        } else {
            Self::plain(body)
        }
    }

    /// Get the plain text representation of this message.
    pub fn find_plain(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/plain")
            .map(|content| content.body.as_ref())
    }

    /// Get the HTML representation of this message.
    pub fn find_html(&self) -> Option<&str> {
        self.iter()
            .find(|content| content.mimetype == "text/html")
            .map(|content| content.body.as_ref())
    }
}

/// The error type returned when trying to construct an empty `MessageContent`.
#[derive(Debug, Error)]
#[non_exhaustive]
#[error("MessageContent cannot be empty")]
pub struct EmptyMessageContentError;

impl TryFrom<Vec<Text>> for MessageContent {
    type Error = EmptyMessageContentError;

    fn try_from(messages: Vec<Text>) -> Result<Self, Self::Error> {
        Self::new(messages).ok_or(EmptyMessageContentError)
    }
}

impl Deref for MessageContent {
    type Target = [Text];

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

/// Text message content.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Text {
    /// The mime type of the `body`.
    #[serde(default = "Text::default_mimetype")]
    pub mimetype: String,

    /// The text content.
    pub body: String,

    /// The language of the text ([MSC3554]).
    ///
    /// This must be a valid language code according to [BCP 47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt).
    ///
    /// [MSC3554]: https://github.com/matrix-org/matrix-spec-proposals/pull/3554
    #[cfg(feature = "unstable-msc3554")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub lang: Option<String>,
}

impl Text {
    /// Creates a new plain text message body.
    pub fn plain(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/plain".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body.
    pub fn html(body: impl Into<String>) -> Self {
        Self {
            mimetype: "text/html".to_owned(),
            body: body.into(),
            #[cfg(feature = "unstable-msc3554")]
            lang: None,
        }
    }

    /// Creates a new HTML-formatted message body by parsing the Markdown in `body`.
    ///
    /// Returns `None` if no Markdown formatting was found.
    #[cfg(feature = "markdown")]
    pub fn markdown(body: impl AsRef<str>) -> Option<Self> {
        let body = body.as_ref();
        let mut html_body = String::new();

        pulldown_cmark::html::push_html(&mut html_body, pulldown_cmark::Parser::new(body));

        (html_body != format!("<p>{}</p>\n", body)).then(|| Self::html(html_body))
    }

    fn default_mimetype() -> String {
        "text/plain".to_owned()
    }
}

/// The error type returned when a conversion to an extensible event type fails.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum TryFromExtensibleError {
    /// A field is missing.
    #[error("missing field `{0}`")]
    MissingField(String),
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::WithLocation;
use graphql_ir::{
    Argument, Condition, ConditionValue, ConstantValue, Directive, ExecutableDefinition,
    FragmentDefinition, FragmentSpread, InlineFragment, LinkedField, OperationDefinition,
    ScalarField, Selection, Value, VariableDefinition,
};
use graphql_syntax::OperationKind;
use interner::StringKey;
use schema::Schema;
use std::fmt::{Result, Write};

const TAB_SIZE: usize = 2;

pub fn print_ir(schema: &Schema, definitions: &[ExecutableDefinition]) -> Vec<String> {
    definitions
        .iter()
        .map(|def| print_definition(&schema, &def))
        .collect()
}

pub fn print_definition(schema: &Schema, definition: &ExecutableDefinition) -> String {
    let mut result = String::new();
    write_definition(schema, definition, &mut result).unwrap();
    result
}

pub fn print_operation(schema: &Schema, operation: &OperationDefinition) -> String {
    let mut result = String::new();
    write_operation(schema, operation, &mut result).unwrap();
    result
}

pub fn print_fragment(schema: &Schema, fragment: &FragmentDefinition) -> String {
    let mut result = String::new();
    write_fragment(schema, fragment, &mut result).unwrap();
    result
}

pub fn print_arguments(schema: &Schema, arguments: &[Argument]) -> String {
    let mut result = String::new();
    write_arguments(schema, arguments, &mut result).unwrap();
    result
}

pub fn print_directives(schema: &Schema, directives: &[Directive]) -> String {
    let mut result = String::new();
    write_directives(schema, directives, &mut result).unwrap();
    result
}

pub fn write_definition(
    schema: &Schema,
    definition: &ExecutableDefinition,
    mut result: &mut impl Write,
) -> Result {
    let printer = Printer::new(&schema, &mut result);
    printer.print_definition(definition)
}

pub fn write_operation(
    schema: &Schema,
    operation: &OperationDefinition,
    mut result: &mut impl Write,
) -> Result {
    let printer = Printer::new(&schema, &mut result);
    printer.print_operation(operation)
}

pub fn write_fragment(
    schema: &Schema,
    fragment: &FragmentDefinition,
    mut result: &mut impl Write,
) -> Result {
    let printer = Printer::new(&schema, &mut result);
    printer.print_fragment(fragment)
}

pub fn write_arguments(
    schema: &Schema,
    arguments: &[Argument],
    mut result: &mut impl Write,
) -> Result {
    let mut printer = Printer::new(&schema, &mut result);
    printer.print_arguments(arguments)
}

pub fn write_directives(
    schema: &Schema,
    directives: &[Directive],
    mut result: &mut impl Write,
) -> Result {
    let mut printer = Printer::new(&schema, &mut result);
    printer.print_directives(directives, None)
}

struct Printer<'schema, 'writer, W: Write> {
    schema: &'schema Schema,
    writer: &'writer mut W,
}

impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> {
    fn new(schema: &'schema Schema, writer: &'writer mut W) -> Self {
        Self { schema, writer }
    }

    fn print_definition(self, definition: &ExecutableDefinition) -> Result {
        match definition {
            ExecutableDefinition::Operation(operation) => self.print_operation(&operation),
            ExecutableDefinition::Fragment(fragment) => self.print_fragment(&fragment),
        }
    }

    fn print_operation(mut self, operation: &OperationDefinition) -> Result {
        let operation_kind = match operation.kind {
            OperationKind::Query => "query",
            OperationKind::Mutation => "mutation",
            OperationKind::Subscription => "subscription",
        };
        let operation_name = operation.name.item;
        write!(self.writer, "{} {}", operation_kind, operation_name)?;
        self.print_variable_definitions(&operation.variable_definitions)?;
        self.print_directives(&operation.directives, None)?;
        self.print_selections(&operation.selections, None, 0)
    }

    fn print_fragment(mut self, fragment: &FragmentDefinition) -> Result {
        let fragment_name = fragment.name.item;
        let type_condition_name = self.schema.get_type_name(fragment.type_condition);
        write!(
            self.writer,
            "fragment {} on {}",
            fragment_name, type_condition_name
        )
        .unwrap();
        self.print_argument_definitions(&fragment.variable_definitions)?;
        self.print_directives(&fragment.directives, None)?;
        self.print_selections(&fragment.selections, None, 0)
    }

    fn print_selection(
        &mut self,
        selection: &Selection,
        conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        match selection {
            Selection::ScalarField(field) => {
                self.print_scalar_field(field, conditions)?;
            }
            Selection::LinkedField(field) => {
                self.print_linked_field(field, conditions, indent_count)?;
            }
            Selection::FragmentSpread(field) => {
                self.print_fragment_spread(field, conditions)?;
            }
            Selection::InlineFragment(field) => {
                self.print_inline_fragment(field, conditions, indent_count)?;
            }
            Selection::Condition(field) => {
                self.print_condition(field, conditions, indent_count)?;
            }
        }
        Ok(())
    }

    fn print_selections(
        &mut self,
        selections: &[Selection],
        conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        let len = selections.len();
        if len > 0 {
            let next_indent_count = indent_count + TAB_SIZE;
            writeln!(self.writer, " {{")?;
            self.print_indentation(next_indent_count)?;

            for (i, selection) in selections.iter().enumerate() {
                self.print_selection(selection, conditions, next_indent_count)?;
                if i != len - 1 {
                    writeln!(self.writer)?;
                    self.print_indentation(next_indent_count)?;
                }
            }

            writeln!(self.writer)?;
            self.print_indentation(indent_count)?;
            write!(self.writer, "}}")?;
        }
        Ok(())
    }

    fn print_scalar_field(
        &mut self,
        field: &ScalarField,
        conditions: Option<&[Condition]>,
    ) -> Result {
        self.print_alias(&field.alias)?;
        let schema_field = self.schema.field(field.definition.item);
        write!(self.writer, "{}", schema_field.name)?;
        self.print_arguments(&field.arguments)?;
        self.print_directives(&field.directives, conditions)
    }

    fn print_linked_field(
        &mut self,
        field: &LinkedField,
        conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        self.print_alias(&field.alias)?;
        let schema_field = self.schema.field(field.definition.item);
        write!(self.writer, "{}", schema_field.name)?;
        self.print_arguments(&field.arguments)?;
        self.print_directives(&field.directives, conditions)?;
        self.print_selections(&field.selections, None, indent_count)?;
        Ok(())
    }

    fn print_fragment_spread(
        &mut self,
        field: &FragmentSpread,
        conditions: Option<&[Condition]>,
    ) -> Result {
        let fragment_name = field.fragment.item;
        write!(self.writer, "...{}", fragment_name)?;
        self.print_directives(&field.directives, conditions)
    }

    fn print_inline_fragment(
        &mut self,
        field: &InlineFragment,
        conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        write!(self.writer, "...")?;
        if let Some(type_condition) = field.type_condition {
            write!(
                self.writer,
                " on {}",
                self.schema.get_type_name(type_condition).lookup(),
            )?;
        };
        self.print_directives(&field.directives, conditions)?;
        self.print_selections(&field.selections, None, indent_count)
    }

    fn print_condition(
        &mut self,
        condition: &Condition,
        parent_conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        let len = condition.selections.len();
        for (i, selection) in condition.selections.iter().enumerate() {
            let next_conditions: Vec<Condition> = match parent_conditions {
                Some(parent_conditions) => {
                    let mut next_conditions: Vec<Condition> = vec![condition.clone()];
                    next_conditions.extend(parent_conditions.iter().cloned());
                    next_conditions
                }
                None => vec![condition.clone()],
            };

            self.print_selection(&selection, Some(&next_conditions), indent_count)?;
            if i != len - 1 {
                writeln!(self.writer)?;
                self.print_indentation(indent_count)?;
            }
        }

        Ok(())
    }

    fn print_directives(
        &mut self,
        directives: &[Directive],
        conditions: Option<&[Condition]>,
    ) -> Result {
        for directive in directives {
            write!(self.writer, " @{}", directive.name.item)?;
            self.print_arguments(&directive.arguments)?;
        }
        if let Some(conditions) = conditions {
            self.print_conditions(conditions)?;
        }
        Ok(())
    }

    fn print_conditions(&mut self, conditions: &[Condition]) -> Result {
        for condition in conditions {
            write!(
                self.writer,
                " @{}",
                if condition.passing_value {
                    "include"
                } else {
                    "skip"
                }
            )?;
            match &condition.value {
                ConditionValue::Constant(value) => {
                    write!(self.writer, "(if: {})", value)?;
                }
                ConditionValue::Variable(variable) => {
                    write!(self.writer, "(if: ${})", variable.name.item)?;
                }
            }
        }
        Ok(())
    }

    fn print_variable_definitions(
        &mut self,
        variable_definitions: &[VariableDefinition],
    ) -> Result {
        let len = variable_definitions.len();
        if len > 0 {
            writeln!(self.writer, "(")?;
            for var_def in variable_definitions.iter() {
                let type_name = self.schema.get_type_string(&var_def.type_);
                self.print_indentation(TAB_SIZE)?;
                write!(self.writer, "${}: {}", var_def.name.item, type_name)?;

                if let Some(default_value) = &var_def.default_value {
                    write!(self.writer, " = ")?;
                    self.print_constant_value(&default_value)?;
                }
                writeln!(self.writer)?;
            }
            write!(self.writer, ")")?;
        }
        Ok(())
    }

    fn print_argument_definitions(
        &mut self,
        argument_definitions: &[VariableDefinition],
    ) -> Result {
        let len = argument_definitions.len();
        if len > 0 {
            writeln!(self.writer, " @argumentDefinitions(")?;
            for arg_def in argument_definitions.iter() {
                let type_name = self.schema.get_type_string(&arg_def.type_);
                self.print_indentation(TAB_SIZE)?;
                write!(
                    self.writer,
                    "{}: {{type: \"{}\"",
                    arg_def.name.item, type_name
                )?;

                if let Some(default_value) = &arg_def.default_value {
                    write!(self.writer, ", defaultValue: ")?;
                    self.print_constant_value(&default_value)?;
                }
                writeln!(self.writer, "}}")?;
            }
            write!(self.writer, ")")?;
        }
        Ok(())
    }

    fn print_arguments(&mut self, arguments: &[Argument]) -> Result {
        let len = arguments.len();
        if len > 0 {
            write!(self.writer, "(")?;
            for (i, argument) in arguments.iter().enumerate() {
                write!(self.writer, "{}: ", argument.name.item)?;

                self.print_value(&argument.value.item)?;

                if i != len - 1 {
                    write!(self.writer, ", ")?;
                }
            }
            write!(self.writer, ")")?;
        }
        Ok(())
    }

    fn print_value(&mut self, val: &Value) -> Result {
        match val {
            Value::Constant(constant_val) => self.print_constant_value(&constant_val),
            Value::Variable(variable_val) => write!(self.writer, "${}", variable_val.name.item),

            Value::Object(object) => {
                let len = object.len();
                if len > 0 {
                    write!(self.writer, "{{")?;
                    for (i, arg) in object.iter().enumerate() {
                        write!(self.writer, "{}: ", arg.name.item)?;
                        self.print_value(&arg.value.item)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "}}")?;
                }
                Ok(())
            }
            Value::List(list) => {
                let len = list.len();
                if len > 0 {
                    write!(self.writer, "[")?;
                    for (i, value) in list.iter().enumerate() {
                        self.print_value(&value)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "]")?;
                }
                Ok(())
            }
        }
    }

    fn print_constant_value(&mut self, constant_val: &ConstantValue) -> Result {
        match &constant_val {
            ConstantValue::String(val) => write!(self.writer, "\"{}\"", val),
            ConstantValue::Enum(val) => write!(self.writer, "{}", val),
            ConstantValue::Float(val) => write!(self.writer, "{}", val),
            ConstantValue::Int(val) => write!(self.writer, "{}", val),
            ConstantValue::Boolean(val) => write!(self.writer, "{}", val),
            ConstantValue::Null() => write!(self.writer, "null"),
            ConstantValue::Object(object) => {
                let len = object.len();
                if len > 0 {
                    write!(self.writer, "{{")?;
                    for (i, arg) in object.iter().enumerate() {
                        write!(self.writer, "{}: ", arg.name.item)?;
                        self.print_constant_value(&arg.value.item)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "}}")?;
                };
                Ok(())
            }
            ConstantValue::List(list) => {
                let len = list.len();
                if len > 0 {
                    write!(self.writer, "[")?;
                    for (i, value) in list.iter().enumerate() {
                        self.print_constant_value(&value)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "]")?;
                };
                Ok(())
            }
        }
    }

    fn print_alias(&mut self, alias: &Option<WithLocation<StringKey>>) -> Result {
        match alias {
            Some(value) => write!(self.writer, "{}: ", value.item),
            None => Ok(()),
        }
    }

    fn print_indentation(&mut self, indent_count: usize) -> Result {
        for _ in 0..indent_count {
            write!(self.writer, " ")?;
        }
        Ok(())
    }
}
<commit_msg>Small refactor for printing conditions<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::WithLocation;
use graphql_ir::{
    Argument, Condition, ConditionValue, ConstantValue, Directive, ExecutableDefinition,
    FragmentDefinition, FragmentSpread, InlineFragment, LinkedField, OperationDefinition,
    ScalarField, Selection, Value, VariableDefinition,
};
use graphql_syntax::OperationKind;
use interner::StringKey;
use schema::Schema;
use std::fmt::{Result, Write};

const TAB_SIZE: usize = 2;

pub fn print_ir(schema: &Schema, definitions: &[ExecutableDefinition]) -> Vec<String> {
    definitions
        .iter()
        .map(|def| print_definition(&schema, &def))
        .collect()
}

pub fn print_definition(schema: &Schema, definition: &ExecutableDefinition) -> String {
    let mut result = String::new();
    write_definition(schema, definition, &mut result).unwrap();
    result
}

pub fn print_operation(schema: &Schema, operation: &OperationDefinition) -> String {
    let mut result = String::new();
    write_operation(schema, operation, &mut result).unwrap();
    result
}

pub fn print_fragment(schema: &Schema, fragment: &FragmentDefinition) -> String {
    let mut result = String::new();
    write_fragment(schema, fragment, &mut result).unwrap();
    result
}

pub fn print_arguments(schema: &Schema, arguments: &[Argument]) -> String {
    let mut result = String::new();
    write_arguments(schema, arguments, &mut result).unwrap();
    result
}

pub fn print_directives(schema: &Schema, directives: &[Directive]) -> String {
    let mut result = String::new();
    write_directives(schema, directives, &mut result).unwrap();
    result
}

pub fn write_definition(
    schema: &Schema,
    definition: &ExecutableDefinition,
    mut result: &mut impl Write,
) -> Result {
    let printer = Printer::new(&schema, &mut result);
    printer.print_definition(definition)
}

pub fn write_operation(
    schema: &Schema,
    operation: &OperationDefinition,
    mut result: &mut impl Write,
) -> Result {
    let printer = Printer::new(&schema, &mut result);
    printer.print_operation(operation)
}

pub fn write_fragment(
    schema: &Schema,
    fragment: &FragmentDefinition,
    mut result: &mut impl Write,
) -> Result {
    let printer = Printer::new(&schema, &mut result);
    printer.print_fragment(fragment)
}

pub fn write_arguments(
    schema: &Schema,
    arguments: &[Argument],
    mut result: &mut impl Write,
) -> Result {
    let mut printer = Printer::new(&schema, &mut result);
    printer.print_arguments(arguments)
}

pub fn write_directives(
    schema: &Schema,
    directives: &[Directive],
    mut result: &mut impl Write,
) -> Result {
    let mut printer = Printer::new(&schema, &mut result);
    printer.print_directives(directives, None)
}

struct Printer<'schema, 'writer, W: Write> {
    schema: &'schema Schema,
    writer: &'writer mut W,
}

impl<'schema, 'writer, W: Write> Printer<'schema, 'writer, W> {
    fn new(schema: &'schema Schema, writer: &'writer mut W) -> Self {
        Self { schema, writer }
    }

    fn print_definition(self, definition: &ExecutableDefinition) -> Result {
        match definition {
            ExecutableDefinition::Operation(operation) => self.print_operation(&operation),
            ExecutableDefinition::Fragment(fragment) => self.print_fragment(&fragment),
        }
    }

    fn print_operation(mut self, operation: &OperationDefinition) -> Result {
        let operation_kind = match operation.kind {
            OperationKind::Query => "query",
            OperationKind::Mutation => "mutation",
            OperationKind::Subscription => "subscription",
        };
        let operation_name = operation.name.item;
        write!(self.writer, "{} {}", operation_kind, operation_name)?;
        self.print_variable_definitions(&operation.variable_definitions)?;
        self.print_directives(&operation.directives, None)?;
        self.print_selections(&operation.selections, 0)
    }

    fn print_fragment(mut self, fragment: &FragmentDefinition) -> Result {
        let fragment_name = fragment.name.item;
        let type_condition_name = self.schema.get_type_name(fragment.type_condition);
        write!(
            self.writer,
            "fragment {} on {}",
            fragment_name, type_condition_name
        )
        .unwrap();
        self.print_argument_definitions(&fragment.variable_definitions)?;
        self.print_directives(&fragment.directives, None)?;
        self.print_selections(&fragment.selections, 0)
    }

    fn print_selections(&mut self, selections: &[Selection], indent_count: usize) -> Result {
        let len = selections.len();
        if len > 0 {
            let next_indent_count = indent_count + TAB_SIZE;
            writeln!(self.writer, " {{")?;
            self.print_indentation(next_indent_count)?;

            for (i, selection) in selections.iter().enumerate() {
                self.print_selection(selection, None, next_indent_count)?;
                if i != len - 1 {
                    writeln!(self.writer)?;
                    self.print_indentation(next_indent_count)?;
                }
            }

            writeln!(self.writer)?;
            self.print_indentation(indent_count)?;
            write!(self.writer, "}}")?;
        }
        Ok(())
    }

    fn print_selection(
        &mut self,
        selection: &Selection,
        conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        match selection {
            Selection::ScalarField(field) => {
                self.print_scalar_field(field, conditions)?;
            }
            Selection::LinkedField(field) => {
                self.print_linked_field(field, conditions, indent_count)?;
            }
            Selection::FragmentSpread(field) => {
                self.print_fragment_spread(field, conditions)?;
            }
            Selection::InlineFragment(field) => {
                self.print_inline_fragment(field, conditions, indent_count)?;
            }
            Selection::Condition(field) => {
                self.print_condition(field, indent_count)?;
            }
        }
        Ok(())
    }

    fn print_scalar_field(
        &mut self,
        field: &ScalarField,
        conditions: Option<&[Condition]>,
    ) -> Result {
        self.print_alias(&field.alias)?;
        let schema_field = self.schema.field(field.definition.item);
        write!(self.writer, "{}", schema_field.name)?;
        self.print_arguments(&field.arguments)?;
        self.print_directives(&field.directives, conditions)
    }

    fn print_linked_field(
        &mut self,
        field: &LinkedField,
        conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        self.print_alias(&field.alias)?;
        let schema_field = self.schema.field(field.definition.item);
        write!(self.writer, "{}", schema_field.name)?;
        self.print_arguments(&field.arguments)?;
        self.print_directives(&field.directives, conditions)?;
        self.print_selections(&field.selections, indent_count)?;
        Ok(())
    }

    fn print_fragment_spread(
        &mut self,
        field: &FragmentSpread,
        conditions: Option<&[Condition]>,
    ) -> Result {
        let fragment_name = field.fragment.item;
        write!(self.writer, "...{}", fragment_name)?;
        self.print_directives(&field.directives, conditions)
    }

    fn print_inline_fragment(
        &mut self,
        field: &InlineFragment,
        conditions: Option<&[Condition]>,
        indent_count: usize,
    ) -> Result {
        write!(self.writer, "...")?;
        if let Some(type_condition) = field.type_condition {
            write!(
                self.writer,
                " on {}",
                self.schema.get_type_name(type_condition).lookup(),
            )?;
        };
        self.print_directives(&field.directives, conditions)?;
        self.print_selections(&field.selections, indent_count)
    }

    fn print_condition(&mut self, condition: &Condition, indent_count: usize) -> Result {
        let mut maybe_current_condition = Some(condition);
        let mut accum_conditions: Vec<Condition> = vec![];
        let mut selections: Vec<&Selection> = vec![];

        // Extract all nested conditions into a flattened list of conditions, and
        // extract the selections from the "leaf" condition
        while let Some(current_condition) = maybe_current_condition {
            accum_conditions.push(current_condition.clone());

            if current_condition.selections.len() == 1 {
                let selection = &current_condition.selections[0];
                if let Selection::Condition(nested_cond) = selection {
                    maybe_current_condition = Some(&nested_cond);
                } else {
                    selections.push(&selection);
                    maybe_current_condition = None;
                }
            } else {
                for selection in current_condition.selections.iter() {
                    if let Selection::Condition(_) = selection {
                        unreachable!("Expected for a Condition to contain either a single Condition node, or non-Condition selections.");
                    }
                    selections.push(selection);
                }
                maybe_current_condition = None;
            }
        }
        accum_conditions.reverse();

        // We don't call print_selections here because the selections for a condition (or set of conditions)
        // aren't printed in the same way. Specifically, we don't need to print curly braces around them
        // and we don't need to increase the indentation. Instead, the output of printing a condition node will
        // expand into printing selections as children of the current parent, with all the relevant
        // condition directives included in each selection.
        let len = selections.len();
        for (i, selection) in selections.iter().enumerate() {
            self.print_selection(&selection, Some(&accum_conditions), indent_count)?;
            if i != len - 1 {
                writeln!(self.writer)?;
                self.print_indentation(indent_count)?;
            }
        }

        Ok(())
    }

    fn print_directives(
        &mut self,
        directives: &[Directive],
        conditions: Option<&[Condition]>,
    ) -> Result {
        for directive in directives {
            write!(self.writer, " @{}", directive.name.item)?;
            self.print_arguments(&directive.arguments)?;
        }
        if let Some(conditions) = conditions {
            self.print_condition_directives(conditions)?;
        }
        Ok(())
    }

    fn print_condition_directives(&mut self, conditions: &[Condition]) -> Result {
        for condition in conditions {
            write!(
                self.writer,
                " @{}",
                if condition.passing_value {
                    "include"
                } else {
                    "skip"
                }
            )?;
            match &condition.value {
                ConditionValue::Constant(value) => {
                    write!(self.writer, "(if: {})", value)?;
                }
                ConditionValue::Variable(variable) => {
                    write!(self.writer, "(if: ${})", variable.name.item)?;
                }
            }
        }
        Ok(())
    }

    fn print_variable_definitions(
        &mut self,
        variable_definitions: &[VariableDefinition],
    ) -> Result {
        let len = variable_definitions.len();
        if len > 0 {
            writeln!(self.writer, "(")?;
            for var_def in variable_definitions.iter() {
                let type_name = self.schema.get_type_string(&var_def.type_);
                self.print_indentation(TAB_SIZE)?;
                write!(self.writer, "${}: {}", var_def.name.item, type_name)?;

                if let Some(default_value) = &var_def.default_value {
                    write!(self.writer, " = ")?;
                    self.print_constant_value(&default_value)?;
                }
                writeln!(self.writer)?;
            }
            write!(self.writer, ")")?;
        }
        Ok(())
    }

    fn print_argument_definitions(
        &mut self,
        argument_definitions: &[VariableDefinition],
    ) -> Result {
        let len = argument_definitions.len();
        if len > 0 {
            writeln!(self.writer, " @argumentDefinitions(")?;
            for arg_def in argument_definitions.iter() {
                let type_name = self.schema.get_type_string(&arg_def.type_);
                self.print_indentation(TAB_SIZE)?;
                write!(
                    self.writer,
                    "{}: {{type: \"{}\"",
                    arg_def.name.item, type_name
                )?;

                if let Some(default_value) = &arg_def.default_value {
                    write!(self.writer, ", defaultValue: ")?;
                    self.print_constant_value(&default_value)?;
                }
                writeln!(self.writer, "}}")?;
            }
            write!(self.writer, ")")?;
        }
        Ok(())
    }

    fn print_arguments(&mut self, arguments: &[Argument]) -> Result {
        let len = arguments.len();
        if len > 0 {
            write!(self.writer, "(")?;
            for (i, argument) in arguments.iter().enumerate() {
                write!(self.writer, "{}: ", argument.name.item)?;

                self.print_value(&argument.value.item)?;

                if i != len - 1 {
                    write!(self.writer, ", ")?;
                }
            }
            write!(self.writer, ")")?;
        }
        Ok(())
    }

    fn print_value(&mut self, val: &Value) -> Result {
        match val {
            Value::Constant(constant_val) => self.print_constant_value(&constant_val),
            Value::Variable(variable_val) => write!(self.writer, "${}", variable_val.name.item),

            Value::Object(object) => {
                let len = object.len();
                if len > 0 {
                    write!(self.writer, "{{")?;
                    for (i, arg) in object.iter().enumerate() {
                        write!(self.writer, "{}: ", arg.name.item)?;
                        self.print_value(&arg.value.item)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "}}")?;
                }
                Ok(())
            }
            Value::List(list) => {
                let len = list.len();
                if len > 0 {
                    write!(self.writer, "[")?;
                    for (i, value) in list.iter().enumerate() {
                        self.print_value(&value)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "]")?;
                }
                Ok(())
            }
        }
    }

    fn print_constant_value(&mut self, constant_val: &ConstantValue) -> Result {
        match &constant_val {
            ConstantValue::String(val) => write!(self.writer, "\"{}\"", val),
            ConstantValue::Enum(val) => write!(self.writer, "{}", val),
            ConstantValue::Float(val) => write!(self.writer, "{}", val),
            ConstantValue::Int(val) => write!(self.writer, "{}", val),
            ConstantValue::Boolean(val) => write!(self.writer, "{}", val),
            ConstantValue::Null() => write!(self.writer, "null"),
            ConstantValue::Object(object) => {
                let len = object.len();
                if len > 0 {
                    write!(self.writer, "{{")?;
                    for (i, arg) in object.iter().enumerate() {
                        write!(self.writer, "{}: ", arg.name.item)?;
                        self.print_constant_value(&arg.value.item)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "}}")?;
                };
                Ok(())
            }
            ConstantValue::List(list) => {
                let len = list.len();
                if len > 0 {
                    write!(self.writer, "[")?;
                    for (i, value) in list.iter().enumerate() {
                        self.print_constant_value(&value)?;

                        if i != len - 1 {
                            write!(self.writer, ", ")?;
                        }
                    }
                    write!(self.writer, "]")?;
                };
                Ok(())
            }
        }
    }

    fn print_alias(&mut self, alias: &Option<WithLocation<StringKey>>) -> Result {
        match alias {
            Some(value) => write!(self.writer, "{}: ", value.item),
            None => Ok(()),
        }
    }

    fn print_indentation(&mut self, indent_count: usize) -> Result {
        for _ in 0..indent_count {
            write!(self.writer, " ")?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io::{self, BufRead};
use std::collections::HashMap;

fn code1() {
    let stdin = io::stdin();

    let mut lines = stdin.lock().lines().fuse();
    let input = match lines.next()  {
        Some(Ok(a))  => a,
        _ => panic!("Couldn t read input.")
    };

    let info = input.trim();
    let splitted = info.split(",");
    let iter = splitted.map(|a| a.to_string().parse().unwrap_or(0));

    let mut result  = 0;
    for num in iter {
        result += num;
    }
    println!("{:?}", result);
}

fn code2() {
    let mut threes = 0;
    let mut two = 0;
    let mut vec: Vec<String> = Vec::new();

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let str_line = line.unwrap().trim().to_string();
        if str_line == "0" {
            println!("exit!");
            break;
        }
        vec.push(str_line);
    }

    let mut saved_characters: HashMap<String, i32> = HashMap::new();
    for info in &vec {
        for charact in info.to_string().chars()  {
            let value = saved_characters.entry(charact.to_string()).or_insert(0);
            *value += 1;
        }

        let temp_threes = saved_characters.values().filter(|val| **val == 3).count();
        let temp_two = saved_characters.values().filter(|val| **val == 2).count();

        threes += temp_threes;
        two += temp_two;
    }
    println!("------------------------------");
    println!("threes: {}", threes);
    println!("twos: {}", two);
}

fn main() {
    //code1();
    code2();
}
<commit_msg>Added example to paint matrix<commit_after>use std::io::{self, BufRead};
use std::collections::HashMap;

fn code1() {
    let stdin = io::stdin();

    let mut lines = stdin.lock().lines().fuse();
    let input = match lines.next()  {
        Some(Ok(a))  => a,
        _ => panic!("Couldn t read input.")
    };

    let info = input.trim();
    let splitted = info.split(",");
    let iter = splitted.map(|a| a.to_string().parse().unwrap_or(0));

    let mut result  = 0;
    for num in iter {
        result += num;
    }
    println!("{:?}", result);
}

fn code2() {
    let mut threes = 0;
    let mut two = 0;
    let mut vec: Vec<String> = Vec::new();

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let str_line = line.unwrap().trim().to_string();
        if str_line == "0" {
            println!("exit!");
            break;
        }
        vec.push(str_line);
    }

    let mut saved_characters: HashMap<String, i32> = HashMap::new();
    for info in &vec {
        for charact in info.to_string().chars()  {
            let value = saved_characters.entry(charact.to_string()).or_insert(0);
            *value += 1;
        }

        let temp_threes = saved_characters.values().filter(|val| **val == 3).count();
        let temp_two = saved_characters.values().filter(|val| **val == 2).count();

        threes += temp_threes;
        two += temp_two;
    }
    println!("------------------------------");
    println!("threes: {}", threes);
    println!("twos: {}", two);
}

fn paint_matrix(matrix: &mut [[&str; 10]; 10]) {
    for (i, row) in  matrix.iter_mut().enumerate() {
        for (y, col) in row.iter_mut().enumerate() {
             print!("{}", col);
        }
        println!();
    }
}

fn code3() {
    let mut vec: Vec<String> = Vec::new();

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let str_line = line.unwrap().trim().to_string();
        if str_line == "0" {
            println!("exit!");
            break;
        }
        vec.push(str_line);
    }
    let mut matrix = [["."; 10];10];
    paint_matrix(&mut matrix);
}

fn main() {
    //code1();
    //code2();
    code3();
}
<|endoftext|>


<commit_before>const POINTERS_IN_NODE: u64 = disk::SECTOR_SIZE / page::POINTER_SIZE;

struct Array<T> {
    root: page::Pointer,
    len: u64,
    _phantom: PhantomData<T>,
}

impl Array<T> {
    fn depth(&self) -> u64 {
        64 - self.len.leading_zeros() as u64
    }

    fn capacity(&self) -> u64 {
        1 << self.depth()
    }

    fn is_leaf(&self) -> bool {
        self.len <= POINTERS_IN_NODE
    }

    fn full_child() -> u64 {
        self.capacity() / POINTERS_IN_NODE
    }

    fn is_full() -> bool {
        self.len == self.capacity()
    }

    fn get_ptr(&self, fs: &fs::State, n: u8) -> Result<page::Pointer, alloc::Error> {
        let buf = fs.read(root)?;
        Ok(little_endian::read(&buf[n * page::POINTER_SIZE..]))
    }

    fn get_child(&self, fs: &fs::State, n: u8) -> Result<Array<T>, alloc::Error> {
        let depth = self.depth();

        Array {
            root: self.get_ptr(fs, n),
            len: if n == POINTERS_IN_NODE - 1 {
                self.len - self.full_child() * POINTERS_IN_NODE
            } else {
                self.full_child()
            },
            _phatom: PhantomData,
        }
    }

    fn get_leaf(&self, fs: &fs::State, mut idx: u64) -> Result<Array<T>, alloc::Error> {
        let mut node = self;
        while !node.is_leaf() {
            idx = idx / node.full_child();
            node = node.get(fs, idx)?;
        }

        Ok(node)
    }

    fn get(&self, fs: &fs::State, idx: u64) -> Result<Option<page::Pointer>, alloc::Error> {
        if idx < self.len {
            if self.len == 1 {
                Ok(Some(self.ptr))
            } else {
                Ok(Some(self.get_leaf(fs, idx)?.get_ptr(idx % POINTERS_IN_NODE)?))
            }
        } else {
            Ok(None)
        }
    }

    fn write<I>(&self, fs: &fs::State, idx: u64, arr: I) -> Result<(), alloc::Error>
        where I: ExactSizeIterator + Iterator<Item = page::Pointer> {
        unimplemented!();
    }

    fn push(&mut self, fs: &fs::State, ptr: page::Pointer) -> Result<(), alloc::Error> {
        if self.len == 0 {
            self.root = ptr;
        } else if self.is_full() {
            let mut buf = disk::SectorBuf::default();
            little_endian::write(self.ptr, &mut buf);
            little_endian::write(&mut buf[page::POINTER_SIZE..], ptr);

            self.ptr = fs.alloc(buf, "array node")?;
        } else {
            let leaf = self.get_leaf(fs, idx)?;
            let buf = fs.read(leaf.ptr)?;

            little_endian::write(&mut buf[page::POINTER_SIZE * (idx % POINTERS_IN_NODE)..], ptr);
        }

        self.len += 1;
    }

    fn pop(&mut self)
}

impl<T: Object + From<page::Pointer>> Object {
    fn gc_visit(&self, fs: &fs::State) -> Result<(), alloc::Error> {
        // TODO: This recursion can be very deep and potentially lead to stack overflow.
        // TODO: This should run in parallel.

        // We make sure that the tree isn't empty. If it is, we have nothing to traverse.
        if self.len != 0 {
            if self.len == 1 {
                // This node is a leaf, so we cast the pointer into an object and traverse it.
                fs.visit(T::from(self.root))?;
            } else {
                // Set the root as reachable.
                fs.set_reachable(self.root)?;
                // Go over the pointers in the root and visit the children.
                for i in 0..self.len / self.full_child() {
                    fs.visit(self.get_child(i)?);
                }
            }
        }
    }
}
<commit_msg>Use suffix trees to store arrays on-disk (WIP).<commit_after>const POINTERS_IN_NODE: u64 = disk::SECTOR_SIZE / page::POINTER_SIZE;

struct Array<T> {
    root: page::Pointer,
    len: u64,
    _phantom: PhantomData<T>,
}

impl Array<T> {
    fn is_leaf(&self) -> bool {
        self.len <= POINTERS_IN_NODE
    }

    fn for_each<F>(&self, fs: &fs::State, range: Range, f: F) -> Result<(), alloc::Error>
        where F: Fn(usize, page::Pointer) -> Result<(), alloc::Error> {
        self.for_each_idx(fs, range.start, range, f)
    }

    fn for_each_idx<F>(&self, fs: &fs::State, idx: usize, range: Range, f: F) -> Result<(), alloc::Error>
        where F: Fn(usize, page::Pointer) -> Result<(), alloc::Error> {
        if self.is_leaf() {
            let buf = fs.read(self.root)?;
            for i in range {
                f(idx + i, little_endian::read(&buf[i * page::POINTER_SIZE..]))?;
            }
        } else {
            let max_child = (self.len + POINTERS_IN_NODE / 2) / POINTERS_IN_NODE;

            self.for_each_idx(idx, range.start..cmp::min(range.end, range.start + POINTERS_IN_NODE), f)?;

            for i in (POINTERS_IN_NODE..range.end).step_by(max_child) {
                self.for_each_idx()
            }
        }
    }
}

impl<T: Object + From<page::Pointer>> Object {
    fn gc_visit(&self, fs: &fs::State) -> Result<(), alloc::Error> {
    }
}
<|endoftext|>