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

use crate::smoke_test_environment::SmokeTestEnvironment;
use cli::client_proxy::ClientProxy;
use diem_config::config::{Identity, NodeConfig, SecureBackend};
use diem_crypto::ed25519::Ed25519PublicKey;
use diem_types::account_address::AccountAddress;
use rust_decimal::{prelude::FromPrimitive, Decimal};
use std::{collections::BTreeMap, fs::File, io::Write, path::PathBuf, str::FromStr};

// TODO(joshlind): Refactor all of these so that they can be contained within the calling
// test files and not shared across all tests.
pub fn compare_balances(
    expected_balances: Vec<(f64, String)>,
    extracted_balances: Vec<String>,
) -> bool {
    if extracted_balances.len() != extracted_balances.len() {
        return false;
    }

    let extracted_balances_dec: BTreeMap<_, _> = extracted_balances
        .into_iter()
        .map(|balance_str| {
            let (currency_code, stripped_str) = if balance_str.ends_with("XUS") {
                ("XUS", balance_str.trim_end_matches("XUS"))
            } else if balance_str.ends_with("XDX") {
                ("XDX", balance_str.trim_end_matches("XDX"))
            } else {
                panic!("Unexpected currency type returned for balance")
            };
            (currency_code, Decimal::from_str(stripped_str).ok())
        })
        .collect();

    expected_balances
        .into_iter()
        .all(|(balance, currency_code)| {
            if let Some(extracted_balance) = extracted_balances_dec.get(currency_code.as_str()) {
                Decimal::from_f64(balance) == *extracted_balance
            } else {
                false
            }
        })
}

/// Sets up a SmokeTestEnvironment with specified size and connects a client
/// proxy to the node_index.
pub fn setup_swarm_and_client_proxy(
    num_nodes: usize,
    node_index: usize,
) -> (SmokeTestEnvironment, ClientProxy) {
    let mut env = SmokeTestEnvironment::new(num_nodes);
    env.validator_swarm.launch();

    let client = env.get_validator_client(node_index, None);
    (env, client)
}

/// Waits for a transaction to be processed by all validator nodes in the smoke
/// test environment.
pub fn wait_for_transaction_on_all_nodes(
    env: &SmokeTestEnvironment,
    num_nodes: usize,
    account: AccountAddress,
    sequence_number: u64,
) {
    for i in 0..num_nodes {
        let client = env.get_validator_client(i, None);
        client
            .wait_for_transaction(account, sequence_number)
            .unwrap();
    }
}

/// This module provides useful functions for operating, handling and managing
/// DiemSwarm instances. It is particularly useful for working with tests that
/// require a SmokeTestEnvironment, as it provides a generic interface across
/// DiemSwarms, regardless of if the swarm is a validator swarm, validator full
/// node swarm, or a public full node swarm.
pub mod diem_swarm_utils {
    use crate::test_utils::fetch_backend_storage;
    use cli::client_proxy::ClientProxy;
    use diem_config::config::{NodeConfig, SecureBackend, WaypointConfig};
    use diem_events_fetcher::DiemEventsFetcher;
    use diem_key_manager::diem_interface::JsonRpcDiemInterface;
    use diem_operational_tool::test_helper::OperationalTool;
    use diem_secure_storage::{KVStorage, Storage};
    use diem_swarm::swarm::DiemSwarm;
    use diem_transaction_replay::DiemDebugger;
    use diem_types::{chain_id::ChainId, waypoint::Waypoint};
    use std::path::PathBuf;

    /// Returns a new client proxy connected to the given swarm at the specified
    /// node index.
    pub fn get_client_proxy(
        swarm: &DiemSwarm,
        node_index: usize,
        diem_root_key_path: &str,
        mnemonic_file_path: PathBuf,
        waypoint: Option<Waypoint>,
    ) -> ClientProxy {
        let port = swarm.get_client_port(node_index);

        let mnemonic_file_path = mnemonic_file_path
            .canonicalize()
            .expect("Unable to get canonical path of mnemonic_file_path")
            .to_str()
            .unwrap()
            .to_string();

        ClientProxy::new(
            ChainId::test(),
            &format!("http://localhost:{}/v1", port),
            &diem_root_key_path,
            &diem_root_key_path,
            &diem_root_key_path,
            false,
            /* faucet server */ None,
            Some(mnemonic_file_path),
            waypoint.unwrap_or(swarm.config.waypoint),
            true,
        )
        .unwrap()
    }

    /// Returns the JSON RPC url pointing to a node at the given
    /// node index.
    pub fn get_json_rpc_url(swarm: &DiemSwarm, node_index: usize) -> String {
        format!("http://127.0.0.1:{}", swarm.get_client_port(node_index))
    }

    /// Returns a JSON RPC based Diem Interface pointing to a node at the given
    /// node index.
    pub fn get_json_rpc_diem_interface(
        swarm: &DiemSwarm,
        node_index: usize,
    ) -> JsonRpcDiemInterface {
        let json_rpc_endpoint = format!("http://127.0.0.1:{}", swarm.get_client_port(node_index));
        JsonRpcDiemInterface::new(json_rpc_endpoint)
    }

    /// Returns a Diem Debugger pointing to a node at the given node index.
    pub fn get_diem_debugger(swarm: &DiemSwarm, node_index: usize) -> DiemDebugger {
        let (node_config, _) = load_node_config(swarm, node_index);
        let swarm_rpc_endpoint =
            format!("http://localhost:{}", node_config.json_rpc.address.port());
        DiemDebugger::json_rpc(swarm_rpc_endpoint.as_str()).unwrap()
    }

    /// Returns a Diem Event Fetcher pointing to a node at the given node index.
    pub fn get_diem_event_fetcher(swarm: &DiemSwarm, node_index: usize) -> DiemEventsFetcher {
        let (node_config, _) = load_node_config(swarm, node_index);
        let swarm_rpc_endpoint =
            format!("http://localhost:{}", node_config.json_rpc.address.port());
        DiemEventsFetcher::new(swarm_rpc_endpoint.as_str()).unwrap()
    }

    /// Returns an operational tool pointing to a validator node at the given node index.
    pub fn get_op_tool(swarm: &DiemSwarm, node_index: usize) -> OperationalTool {
        OperationalTool::new(
            format!("http://127.0.0.1:{}", swarm.get_client_port(node_index)),
            ChainId::test(),
        )
    }

    /// Loads the nodes's storage backend identified by the node index in the given swarm.
    pub fn load_backend_storage(swarm: &DiemSwarm, node_index: usize) -> SecureBackend {
        let (node_config, _) = load_node_config(swarm, node_index);
        fetch_backend_storage(&node_config, None)
    }

    /// Loads the diem root's storage backend identified by the node index in the given swarm.
    pub fn load_diem_root_storage(swarm: &DiemSwarm, node_index: usize) -> SecureBackend {
        let (node_config, _) = load_node_config(swarm, node_index);
        fetch_backend_storage(&node_config, Some("diem_root".to_string()))
    }

    /// Loads the node config for the validator at the specified index. Also returns the node
    /// config path.
    pub fn load_node_config(swarm: &DiemSwarm, node_index: usize) -> (NodeConfig, PathBuf) {
        let node_config_path = swarm.config.config_files.get(node_index).unwrap();
        let node_config = NodeConfig::load(&node_config_path).unwrap();
        (node_config, node_config_path.clone())
    }

    /// Saves the node config for the node at the specified index in the given swarm.
    pub fn save_node_config(node_config: &mut NodeConfig, swarm: &DiemSwarm, node_index: usize) {
        let node_config_path = swarm.config.config_files.get(node_index).unwrap();
        node_config.save(node_config_path).unwrap();
    }

    pub fn insert_waypoint(node_config: &mut NodeConfig, waypoint: Waypoint) {
        let f = |backend: &SecureBackend| {
            let mut storage: Storage = backend.into();
            storage
                .set(diem_global_constants::WAYPOINT, waypoint)
                .expect("Unable to write waypoint");
            storage
                .set(diem_global_constants::GENESIS_WAYPOINT, waypoint)
                .expect("Unable to write waypoint");
        };
        let backend = &node_config.consensus.safety_rules.backend;
        f(backend);
        match &node_config.base.waypoint {
            WaypointConfig::FromStorage(backend) => {
                f(backend);
            }
            _ => panic!("unexpected waypoint from node config"),
        }
    }
}

/// Loads the node's storage backend from the given node config. If a namespace
/// is specified, the storage namespace will be overridden.
fn fetch_backend_storage(
    node_config: &NodeConfig,
    overriding_namespace: Option<String>,
) -> SecureBackend {
    if let Identity::FromStorage(storage_identity) =
        &node_config.validator_network.as_ref().unwrap().identity
    {
        match storage_identity.backend.clone() {
            SecureBackend::OnDiskStorage(mut config) => {
                if let Some(namespace) = overriding_namespace {
                    config.namespace = Some(namespace);
                }
                SecureBackend::OnDiskStorage(config)
            }
            _ => unimplemented!("On-disk storage is the only backend supported in smoke tests"),
        }
    } else {
        panic!("Couldn't load identity from storage");
    }
}

/// Writes a given public key to a file specified by the given path using hex encoding.
/// Contents are written using utf-8 encoding and a newline is appended to ensure that
/// whitespace can be handled by tests.
pub fn write_key_to_file_hex_format(key: &Ed25519PublicKey, key_file_path: PathBuf) {
    let hex_encoded_key = hex::encode(key.to_bytes());
    let key_and_newline = hex_encoded_key + "\n";
    let mut file = File::create(key_file_path).unwrap();
    file.write_all(&key_and_newline.as_bytes()).unwrap();
}

/// Writes a given public key to a file specified by the given path using bcs encoding.
pub fn write_key_to_file_bcs_format(key: &Ed25519PublicKey, key_file_path: PathBuf) {
    let bcs_encoded_key = bcs::to_bytes(&key).unwrap();
    let mut file = File::create(key_file_path).unwrap();
    file.write_all(&bcs_encoded_key).unwrap();
}
<commit_msg>smoke-test: use swarm's root storage<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::smoke_test_environment::SmokeTestEnvironment;
use cli::client_proxy::ClientProxy;
use diem_config::config::{Identity, NodeConfig, SecureBackend};
use diem_crypto::ed25519::Ed25519PublicKey;
use diem_types::account_address::AccountAddress;
use rust_decimal::{prelude::FromPrimitive, Decimal};
use std::{collections::BTreeMap, fs::File, io::Write, path::PathBuf, str::FromStr};

// TODO(joshlind): Refactor all of these so that they can be contained within the calling
// test files and not shared across all tests.
pub fn compare_balances(
    expected_balances: Vec<(f64, String)>,
    extracted_balances: Vec<String>,
) -> bool {
    if extracted_balances.len() != extracted_balances.len() {
        return false;
    }

    let extracted_balances_dec: BTreeMap<_, _> = extracted_balances
        .into_iter()
        .map(|balance_str| {
            let (currency_code, stripped_str) = if balance_str.ends_with("XUS") {
                ("XUS", balance_str.trim_end_matches("XUS"))
            } else if balance_str.ends_with("XDX") {
                ("XDX", balance_str.trim_end_matches("XDX"))
            } else {
                panic!("Unexpected currency type returned for balance")
            };
            (currency_code, Decimal::from_str(stripped_str).ok())
        })
        .collect();

    expected_balances
        .into_iter()
        .all(|(balance, currency_code)| {
            if let Some(extracted_balance) = extracted_balances_dec.get(currency_code.as_str()) {
                Decimal::from_f64(balance) == *extracted_balance
            } else {
                false
            }
        })
}

/// Sets up a SmokeTestEnvironment with specified size and connects a client
/// proxy to the node_index.
pub fn setup_swarm_and_client_proxy(
    num_nodes: usize,
    node_index: usize,
) -> (SmokeTestEnvironment, ClientProxy) {
    let mut env = SmokeTestEnvironment::new(num_nodes);
    env.validator_swarm.launch();

    let client = env.get_validator_client(node_index, None);
    (env, client)
}

/// Waits for a transaction to be processed by all validator nodes in the smoke
/// test environment.
pub fn wait_for_transaction_on_all_nodes(
    env: &SmokeTestEnvironment,
    num_nodes: usize,
    account: AccountAddress,
    sequence_number: u64,
) {
    for i in 0..num_nodes {
        let client = env.get_validator_client(i, None);
        client
            .wait_for_transaction(account, sequence_number)
            .unwrap();
    }
}

/// This module provides useful functions for operating, handling and managing
/// DiemSwarm instances. It is particularly useful for working with tests that
/// require a SmokeTestEnvironment, as it provides a generic interface across
/// DiemSwarms, regardless of if the swarm is a validator swarm, validator full
/// node swarm, or a public full node swarm.
pub mod diem_swarm_utils {
    use crate::test_utils::fetch_backend_storage;
    use cli::client_proxy::ClientProxy;
    use diem_config::config::{NodeConfig, SecureBackend, WaypointConfig};
    use diem_events_fetcher::DiemEventsFetcher;
    use diem_key_manager::diem_interface::JsonRpcDiemInterface;
    use diem_operational_tool::test_helper::OperationalTool;
    use diem_secure_storage::{KVStorage, Storage};
    use diem_swarm::swarm::DiemSwarm;
    use diem_transaction_replay::DiemDebugger;
    use diem_types::{chain_id::ChainId, waypoint::Waypoint};
    use std::path::PathBuf;

    /// Returns a new client proxy connected to the given swarm at the specified
    /// node index.
    pub fn get_client_proxy(
        swarm: &DiemSwarm,
        node_index: usize,
        diem_root_key_path: &str,
        mnemonic_file_path: PathBuf,
        waypoint: Option<Waypoint>,
    ) -> ClientProxy {
        let port = swarm.get_client_port(node_index);

        let mnemonic_file_path = mnemonic_file_path
            .canonicalize()
            .expect("Unable to get canonical path of mnemonic_file_path")
            .to_str()
            .unwrap()
            .to_string();

        ClientProxy::new(
            ChainId::test(),
            &format!("http://localhost:{}/v1", port),
            &diem_root_key_path,
            &diem_root_key_path,
            &diem_root_key_path,
            false,
            /* faucet server */ None,
            Some(mnemonic_file_path),
            waypoint.unwrap_or(swarm.config.waypoint),
            true,
        )
        .unwrap()
    }

    /// Returns the JSON RPC url pointing to a node at the given
    /// node index.
    pub fn get_json_rpc_url(swarm: &DiemSwarm, node_index: usize) -> String {
        format!("http://127.0.0.1:{}", swarm.get_client_port(node_index))
    }

    /// Returns a JSON RPC based Diem Interface pointing to a node at the given
    /// node index.
    pub fn get_json_rpc_diem_interface(
        swarm: &DiemSwarm,
        node_index: usize,
    ) -> JsonRpcDiemInterface {
        let json_rpc_endpoint = format!("http://127.0.0.1:{}", swarm.get_client_port(node_index));
        JsonRpcDiemInterface::new(json_rpc_endpoint)
    }

    /// Returns a Diem Debugger pointing to a node at the given node index.
    pub fn get_diem_debugger(swarm: &DiemSwarm, node_index: usize) -> DiemDebugger {
        let (node_config, _) = load_node_config(swarm, node_index);
        let swarm_rpc_endpoint =
            format!("http://localhost:{}", node_config.json_rpc.address.port());
        DiemDebugger::json_rpc(swarm_rpc_endpoint.as_str()).unwrap()
    }

    /// Returns a Diem Event Fetcher pointing to a node at the given node index.
    pub fn get_diem_event_fetcher(swarm: &DiemSwarm, node_index: usize) -> DiemEventsFetcher {
        let (node_config, _) = load_node_config(swarm, node_index);
        let swarm_rpc_endpoint =
            format!("http://localhost:{}", node_config.json_rpc.address.port());
        DiemEventsFetcher::new(swarm_rpc_endpoint.as_str()).unwrap()
    }

    /// Returns an operational tool pointing to a validator node at the given node index.
    pub fn get_op_tool(swarm: &DiemSwarm, node_index: usize) -> OperationalTool {
        OperationalTool::new(
            format!("http://127.0.0.1:{}", swarm.get_client_port(node_index)),
            ChainId::test(),
        )
    }

    /// Loads the nodes's storage backend identified by the node index in the given swarm.
    pub fn load_backend_storage(swarm: &DiemSwarm, node_index: usize) -> SecureBackend {
        let (node_config, _) = load_node_config(swarm, node_index);
        fetch_backend_storage(&node_config, None)
    }

    /// Loads the diem root's storage backend identified by the node index in the given swarm.
    pub fn load_diem_root_storage(swarm: &DiemSwarm, _node_index: usize) -> SecureBackend {
        SecureBackend::OnDiskStorage(swarm.config.root_storage.clone())
    }

    /// Loads the node config for the validator at the specified index. Also returns the node
    /// config path.
    pub fn load_node_config(swarm: &DiemSwarm, node_index: usize) -> (NodeConfig, PathBuf) {
        let node_config_path = swarm.config.config_files.get(node_index).unwrap();
        let node_config = NodeConfig::load(&node_config_path).unwrap();
        (node_config, node_config_path.clone())
    }

    /// Saves the node config for the node at the specified index in the given swarm.
    pub fn save_node_config(node_config: &mut NodeConfig, swarm: &DiemSwarm, node_index: usize) {
        let node_config_path = swarm.config.config_files.get(node_index).unwrap();
        node_config.save(node_config_path).unwrap();
    }

    pub fn insert_waypoint(node_config: &mut NodeConfig, waypoint: Waypoint) {
        let f = |backend: &SecureBackend| {
            let mut storage: Storage = backend.into();
            storage
                .set(diem_global_constants::WAYPOINT, waypoint)
                .expect("Unable to write waypoint");
            storage
                .set(diem_global_constants::GENESIS_WAYPOINT, waypoint)
                .expect("Unable to write waypoint");
        };
        let backend = &node_config.consensus.safety_rules.backend;
        f(backend);
        match &node_config.base.waypoint {
            WaypointConfig::FromStorage(backend) => {
                f(backend);
            }
            _ => panic!("unexpected waypoint from node config"),
        }
    }
}

/// Loads the node's storage backend from the given node config. If a namespace
/// is specified, the storage namespace will be overridden.
fn fetch_backend_storage(
    node_config: &NodeConfig,
    overriding_namespace: Option<String>,
) -> SecureBackend {
    if let Identity::FromStorage(storage_identity) =
        &node_config.validator_network.as_ref().unwrap().identity
    {
        match storage_identity.backend.clone() {
            SecureBackend::OnDiskStorage(mut config) => {
                if let Some(namespace) = overriding_namespace {
                    config.namespace = Some(namespace);
                }
                SecureBackend::OnDiskStorage(config)
            }
            _ => unimplemented!("On-disk storage is the only backend supported in smoke tests"),
        }
    } else {
        panic!("Couldn't load identity from storage");
    }
}

/// Writes a given public key to a file specified by the given path using hex encoding.
/// Contents are written using utf-8 encoding and a newline is appended to ensure that
/// whitespace can be handled by tests.
pub fn write_key_to_file_hex_format(key: &Ed25519PublicKey, key_file_path: PathBuf) {
    let hex_encoded_key = hex::encode(key.to_bytes());
    let key_and_newline = hex_encoded_key + "\n";
    let mut file = File::create(key_file_path).unwrap();
    file.write_all(&key_and_newline.as_bytes()).unwrap();
}

/// Writes a given public key to a file specified by the given path using bcs encoding.
pub fn write_key_to_file_bcs_format(key: &Ed25519PublicKey, key_file_path: PathBuf) {
    let bcs_encoded_key = bcs::to_bytes(&key).unwrap();
    let mut file = File::create(key_file_path).unwrap();
    file.write_all(&bcs_encoded_key).unwrap();
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![feature(start)]
#![feature(core_intrinsics)]
#![feature(panic_info_message)]
#![no_std]
extern crate libc;
extern crate secp256k1;
extern crate serde_cbor;

use core::fmt::{self, write, Write};
use core::intrinsics;
use core::panic::PanicInfo;

use secp256k1::rand::{self, RngCore};
use secp256k1::serde::Serialize;
use secp256k1::*;

use serde_cbor::de;
use serde_cbor::ser::SliceWrite;
use serde_cbor::Serializer;

struct FakeRng;
impl RngCore for FakeRng {
    fn next_u32(&mut self) -> u32 {
        57
    }
    fn next_u64(&mut self) -> u64 {
        57
    }
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
        for i in dest {
            *i = 57;
        }
        Ok(())
    }
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.try_fill_bytes(dest).unwrap();
    }
}

#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    let mut buf = [0u8; 600_000];
    let size = Secp256k1::preallocate_size();
    unsafe { libc::printf("needed size: %d\n\0".as_ptr() as _, size) };

    let mut secp = Secp256k1::preallocated_new(&mut buf).unwrap();
    secp.randomize(&mut FakeRng);
    let secret_key = SecretKey::new(&mut FakeRng);
    let public_key = PublicKey::from_secret_key(&secp, &secret_key);
    let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");

    let sig = secp.sign(&message, &secret_key);
    assert!(secp.verify(&message, &sig, &public_key).is_ok());

    let mut cbor_ser = [0u8; 100];
    let writer = SliceWrite::new(&mut cbor_ser[..]);
    let mut ser = Serializer::new(writer);
    sig.serialize(&mut ser).unwrap();
    let size = ser.into_inner().bytes_written();
    let new_sig: Signature = de::from_mut_slice(&mut cbor_ser[..size]).unwrap();
    assert_eq!(sig, new_sig);

    unsafe { libc::printf("Verified Successfully!\n\0".as_ptr() as _) };
    0
}

// These functions are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

// This function may be needed based on the compilation target.
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {}

const MAX_PRINT: usize = 511;
struct Print {
    loc: usize,
    buf: [u8; 512],
}

impl Print {
    pub fn new() -> Self {
        Self {
            loc: 0,
            buf: [0u8; 512],
        }
    }

    pub fn print(&self) {
        unsafe {
            let newline = "\n";
            libc::printf(self.buf.as_ptr() as _);
            libc::printf(newline.as_ptr() as _);
        }
    }
}

impl Write for Print {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        let curr = self.loc;
        if curr + s.len() > MAX_PRINT {
            unsafe {
                libc::printf("overflow\n\0".as_ptr() as _);
                intrinsics::abort();
            }
        }
        self.loc += s.len();
        self.buf[curr..self.loc].copy_from_slice(s.as_bytes());
        Ok(())
    }
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    unsafe { libc::printf("shi1\n\0".as_ptr() as _) };
    let msg = info.message().unwrap();
    let mut buf = Print::new();
    write(&mut buf, *msg).unwrap();
    buf.print();
    unsafe { intrinsics::abort() }
}
<commit_msg>DOC: Added documentation to no-std test<commit_after>// Bitcoin secp256k1 bindings
// Written in 2019 by
//   Elichai Turkel
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # secp256k1 no-std test.
//! This binary is a short smallest rust code to produce a working binary *without libstd*.
//! This gives us 2 things:
//!     1. Test that the parts of the code that should work in a no-std enviroment actually work.
//!     2. Test that we don't accidentally import libstd into `secp256k1`.
//!
//! The first is tested using the following command `cargo run --release | grep -q "Verified Successfully"`.
//! (Making sure that it successfully printed that. i.e. it didn't abort before that).
//!
//! The second is tested by the fact that it compiles. if we accidentally link against libstd we should see the following error:
//! `error[E0152]: duplicate lang item found`.
//! Example:
//! ```
//! error[E0152]: duplicate lang item found: `eh_personality`.
//!   --> src/main.rs:37:1
//!    |
//! 37 | pub extern "C" fn rust_eh_personality() {}
//!    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//!    |
//!    = note: first defined in crate `panic_unwind` (which `std` depends on).
//! ```
//!
//! Notes:
//!     * Requires `panic=abort` and `--release` to not depend on libunwind(which is provided usually by libstd) https://github.com/rust-lang/rust/issues/47493
//!     * Requires linking with `libc` for calling `printf`.
//!

#![feature(lang_items)]
#![feature(start)]
#![feature(core_intrinsics)]
#![feature(panic_info_message)]
#![no_std]
extern crate libc;
extern crate secp256k1;
extern crate serde_cbor;

use core::fmt::{self, write, Write};
use core::intrinsics;
use core::panic::PanicInfo;

use secp256k1::rand::{self, RngCore};
use secp256k1::serde::Serialize;
use secp256k1::*;

use serde_cbor::de;
use serde_cbor::ser::SliceWrite;
use serde_cbor::Serializer;

struct FakeRng;
impl RngCore for FakeRng {
    fn next_u32(&mut self) -> u32 {
        57
    }
    fn next_u64(&mut self) -> u64 {
        57
    }
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
        for i in dest {
            *i = 57;
        }
        Ok(())
    }
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.try_fill_bytes(dest).unwrap();
    }
}

#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    let mut buf = [0u8; 600_000];
    let size = Secp256k1::preallocate_size();
    unsafe { libc::printf("needed size: %d\n\0".as_ptr() as _, size) };

    let mut secp = Secp256k1::preallocated_new(&mut buf).unwrap();
    secp.randomize(&mut FakeRng);
    let secret_key = SecretKey::new(&mut FakeRng);
    let public_key = PublicKey::from_secret_key(&secp, &secret_key);
    let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");

    let sig = secp.sign(&message, &secret_key);
    assert!(secp.verify(&message, &sig, &public_key).is_ok());

    let mut cbor_ser = [0u8; 100];
    let writer = SliceWrite::new(&mut cbor_ser[..]);
    let mut ser = Serializer::new(writer);
    sig.serialize(&mut ser).unwrap();
    let size = ser.into_inner().bytes_written();
    let new_sig: Signature = de::from_mut_slice(&mut cbor_ser[..size]).unwrap();
    assert_eq!(sig, new_sig);

    unsafe { libc::printf("Verified Successfully!\n\0".as_ptr() as _) };
    0
}

// These functions are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

// This function may be needed based on the compilation target.
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {}

const MAX_PRINT: usize = 511;
struct Print {
    loc: usize,
    buf: [u8; 512],
}

impl Print {
    pub fn new() -> Self {
        Self {
            loc: 0,
            buf: [0u8; 512],
        }
    }

    pub fn print(&self) {
        unsafe {
            let newline = "\n";
            libc::printf(self.buf.as_ptr() as _);
            libc::printf(newline.as_ptr() as _);
        }
    }
}

impl Write for Print {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        let curr = self.loc;
        if curr + s.len() > MAX_PRINT {
            unsafe {
                libc::printf("overflow\n\0".as_ptr() as _);
                intrinsics::abort();
            }
        }
        self.loc += s.len();
        self.buf[curr..self.loc].copy_from_slice(s.as_bytes());
        Ok(())
    }
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    unsafe { libc::printf("shi1\n\0".as_ptr() as _) };
    let msg = info.message().unwrap();
    let mut buf = Print::new();
    write(&mut buf, *msg).unwrap();
    buf.print();
    unsafe { intrinsics::abort() }
}
<|endoftext|>


<commit_before>use crate::models::helpers::with_count::*;
use crate::util::errors::{cargo_err, AppResult};
use diesel::pg::Pg;
use diesel::prelude::*;
use diesel::query_builder::*;
use diesel::query_dsl::LoadQuery;
use diesel::sql_types::BigInt;
use indexmap::IndexMap;

#[derive(Debug, Clone, Copy)]
pub(crate) enum Page {
    Numeric(u32),
    Unspecified,
}

impl Page {
    fn new(params: &IndexMap<String, String>) -> AppResult<Self> {
        if let Some(s) = params.get("page") {
            let numeric_page = s.parse()?;
            if numeric_page < 1 {
                return Err(cargo_err(&format_args!(
                    "page indexing starts from 1, page {} is invalid",
                    numeric_page,
                )));
            }

            Ok(Page::Numeric(numeric_page))
        } else {
            Ok(Page::Unspecified)
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub(crate) struct PaginationOptions {
    page: Page,
    pub(crate) per_page: u32,
}

impl PaginationOptions {
    pub(crate) fn new(params: &IndexMap<String, String>) -> AppResult<Self> {
        const DEFAULT_PER_PAGE: u32 = 10;
        const MAX_PER_PAGE: u32 = 100;

        let per_page = params
            .get("per_page")
            .map(|s| s.parse())
            .unwrap_or(Ok(DEFAULT_PER_PAGE))?;

        if per_page > MAX_PER_PAGE {
            return Err(cargo_err(&format_args!(
                "cannot request more than {} items",
                MAX_PER_PAGE,
            )));
        }

        Ok(Self {
            page: Page::new(params)?,
            per_page,
        })
    }

    pub(crate) fn offset(&self) -> Option<u32> {
        if let Page::Numeric(p) = self.page {
            Some((p - 1) * self.per_page)
        } else {
            None
        }
    }
}

pub(crate) trait Paginate: Sized {
    fn paginate(self, params: &IndexMap<String, String>) -> AppResult<PaginatedQuery<Self>> {
        Ok(PaginatedQuery {
            query: self,
            options: PaginationOptions::new(params)?,
        })
    }
}

impl<T> Paginate for T {}

pub struct Paginated<T> {
    records_and_total: Vec<WithCount<T>>,
    options: PaginationOptions,
}

impl<T> Paginated<T> {
    pub(crate) fn total(&self) -> Option<i64> {
        Some(
            self.records_and_total
                .get(0)
                .map(|row| row.total)
                .unwrap_or_default(),
        )
    }

    pub(crate) fn next_page_params(&self) -> Option<IndexMap<String, String>> {
        if self.records_and_total.len() < self.options.per_page as usize {
            return None;
        }

        let mut opts = IndexMap::new();
        match self.options.page {
            Page::Numeric(n) => opts.insert("page".into(), (n + 1).to_string()),
            Page::Unspecified => opts.insert("page".into(), 2.to_string()),
        };
        Some(opts)
    }

    pub(crate) fn prev_page_params(&self) -> Option<IndexMap<String, String>> {
        if let Page::Numeric(1) | Page::Unspecified = self.options.page {
            return None;
        }

        let mut opts = IndexMap::new();
        match self.options.page {
            Page::Numeric(n) => opts.insert("page".into(), (n - 1).to_string()),
            Page::Unspecified => unreachable!(),
        };
        Some(opts)
    }

    pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
        self.records_and_total.iter().map(|row| &row.record)
    }
}

impl<T: 'static> IntoIterator for Paginated<T> {
    type IntoIter = Box<dyn Iterator<Item = Self::Item>>;
    type Item = T;

    fn into_iter(self) -> Self::IntoIter {
        Box::new(self.records_and_total.into_iter().map(|row| row.record))
    }
}

#[derive(Debug)]
pub(crate) struct PaginatedQuery<T> {
    query: T,
    options: PaginationOptions,
}

impl<T> PaginatedQuery<T> {
    pub(crate) fn load<U>(self, conn: &PgConnection) -> QueryResult<Paginated<U>>
    where
        Self: LoadQuery<PgConnection, WithCount<U>>,
    {
        let options = self.options;
        let records_and_total = self.internal_load(conn)?;
        Ok(Paginated {
            records_and_total,
            options,
        })
    }
}

impl<T> QueryId for PaginatedQuery<T> {
    const HAS_STATIC_QUERY_ID: bool = false;
    type QueryId = ();
}

impl<T: Query> Query for PaginatedQuery<T> {
    type SqlType = (T::SqlType, BigInt);
}

impl<T, DB> RunQueryDsl<DB> for PaginatedQuery<T> {}

impl<T> QueryFragment<Pg> for PaginatedQuery<T>
where
    T: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<'_, Pg>) -> QueryResult<()> {
        out.push_sql("SELECT *, COUNT(*) OVER () FROM (");
        self.query.walk_ast(out.reborrow())?;
        out.push_sql(") t LIMIT ");
        out.push_bind_param::<BigInt, _>(&i64::from(self.options.per_page))?;
        if let Some(offset) = self.options.offset() {
            out.push_sql(" OFFSET ");
            out.push_bind_param::<BigInt, _>(&i64::from(offset))?;
        }
        Ok(())
    }
}
<commit_msg>Convert pagination ISE into a Bad Request response<commit_after>use crate::models::helpers::with_count::*;
use crate::util::errors::{cargo_err, AppResult};
use diesel::pg::Pg;
use diesel::prelude::*;
use diesel::query_builder::*;
use diesel::query_dsl::LoadQuery;
use diesel::sql_types::BigInt;
use indexmap::IndexMap;

#[derive(Debug, Clone, Copy)]
pub(crate) enum Page {
    Numeric(u32),
    Unspecified,
}

impl Page {
    fn new(params: &IndexMap<String, String>) -> AppResult<Self> {
        if let Some(s) = params.get("page") {
            let numeric_page = s.parse().map_err(|e| bad_request(&e))?;
            if numeric_page < 1 {
                return Err(cargo_err(&format_args!(
                    "page indexing starts from 1, page {} is invalid",
                    numeric_page,
                )));
            }

            Ok(Page::Numeric(numeric_page))
        } else {
            Ok(Page::Unspecified)
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub(crate) struct PaginationOptions {
    page: Page,
    pub(crate) per_page: u32,
}

impl PaginationOptions {
    pub(crate) fn new(params: &IndexMap<String, String>) -> AppResult<Self> {
        const DEFAULT_PER_PAGE: u32 = 10;
        const MAX_PER_PAGE: u32 = 100;

        let per_page = params
            .get("per_page")
            .map(|s| s.parse().map_err(|e| bad_request(&e)))
            .unwrap_or(Ok(DEFAULT_PER_PAGE))?;

        if per_page > MAX_PER_PAGE {
            return Err(cargo_err(&format_args!(
                "cannot request more than {} items",
                MAX_PER_PAGE,
            )));
        }

        Ok(Self {
            page: Page::new(params)?,
            per_page,
        })
    }

    pub(crate) fn offset(&self) -> Option<u32> {
        if let Page::Numeric(p) = self.page {
            Some((p - 1) * self.per_page)
        } else {
            None
        }
    }
}

pub(crate) trait Paginate: Sized {
    fn paginate(self, params: &IndexMap<String, String>) -> AppResult<PaginatedQuery<Self>> {
        Ok(PaginatedQuery {
            query: self,
            options: PaginationOptions::new(params)?,
        })
    }
}

impl<T> Paginate for T {}

pub struct Paginated<T> {
    records_and_total: Vec<WithCount<T>>,
    options: PaginationOptions,
}

impl<T> Paginated<T> {
    pub(crate) fn total(&self) -> Option<i64> {
        Some(
            self.records_and_total
                .get(0)
                .map(|row| row.total)
                .unwrap_or_default(),
        )
    }

    pub(crate) fn next_page_params(&self) -> Option<IndexMap<String, String>> {
        if self.records_and_total.len() < self.options.per_page as usize {
            return None;
        }

        let mut opts = IndexMap::new();
        match self.options.page {
            Page::Numeric(n) => opts.insert("page".into(), (n + 1).to_string()),
            Page::Unspecified => opts.insert("page".into(), 2.to_string()),
        };
        Some(opts)
    }

    pub(crate) fn prev_page_params(&self) -> Option<IndexMap<String, String>> {
        if let Page::Numeric(1) | Page::Unspecified = self.options.page {
            return None;
        }

        let mut opts = IndexMap::new();
        match self.options.page {
            Page::Numeric(n) => opts.insert("page".into(), (n - 1).to_string()),
            Page::Unspecified => unreachable!(),
        };
        Some(opts)
    }

    pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
        self.records_and_total.iter().map(|row| &row.record)
    }
}

impl<T: 'static> IntoIterator for Paginated<T> {
    type IntoIter = Box<dyn Iterator<Item = Self::Item>>;
    type Item = T;

    fn into_iter(self) -> Self::IntoIter {
        Box::new(self.records_and_total.into_iter().map(|row| row.record))
    }
}

#[derive(Debug)]
pub(crate) struct PaginatedQuery<T> {
    query: T,
    options: PaginationOptions,
}

impl<T> PaginatedQuery<T> {
    pub(crate) fn load<U>(self, conn: &PgConnection) -> QueryResult<Paginated<U>>
    where
        Self: LoadQuery<PgConnection, WithCount<U>>,
    {
        let options = self.options;
        let records_and_total = self.internal_load(conn)?;
        Ok(Paginated {
            records_and_total,
            options,
        })
    }
}

impl<T> QueryId for PaginatedQuery<T> {
    const HAS_STATIC_QUERY_ID: bool = false;
    type QueryId = ();
}

impl<T: Query> Query for PaginatedQuery<T> {
    type SqlType = (T::SqlType, BigInt);
}

impl<T, DB> RunQueryDsl<DB> for PaginatedQuery<T> {}

impl<T> QueryFragment<Pg> for PaginatedQuery<T>
where
    T: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<'_, Pg>) -> QueryResult<()> {
        out.push_sql("SELECT *, COUNT(*) OVER () FROM (");
        self.query.walk_ast(out.reborrow())?;
        out.push_sql(") t LIMIT ");
        out.push_bind_param::<BigInt, _>(&i64::from(self.options.per_page))?;
        if let Some(offset) = self.options.offset() {
            out.push_sql(" OFFSET ");
            out.push_bind_param::<BigInt, _>(&i64::from(offset))?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use draw::{self, Drawing};
use draw::mesh::vertex::IntoVertex;
use draw::properties::{Draw, Drawn, IntoDrawn, Primitive, SetOrientation, SetPosition};
use draw::properties::spatial::{self, orientation, position};
use geom;
use math::BaseFloat;
use mesh::vertex::{WithColor, WithTexCoords};
use std::{iter, ops};

/// The mesh type prior to being initialised with vertices or indices.
#[derive(Clone, Debug, Default)]
pub struct Vertexless;

/// Properties related to drawing an arbitrary mesh of colours, geometry and texture.
#[derive(Clone, Debug)]
pub struct Mesh<S = geom::DefaultScalar> {
    position: position::Properties<S>,
    orientation: orientation::Properties<S>,
    vertex_data_ranges: draw::IntermediaryVertexDataRanges,
    index_range: ops::Range<usize>,
}

// A simple iterator for flattening a fixed-size array of indices.
struct FlattenIndices<I> {
    iter: I,
    index: usize,
    current: [usize; 3],
}

impl Vertexless {
    /// Describe the mesh with a sequence of triangles.
    ///
    /// Each triangle may be composed of any vertex type that may be converted directly into the
    /// `draw;;mesh::vertex` type.
    pub fn tris<S, I, V>(
        self,
        mesh: &mut draw::IntermediaryMesh<S>,
        tris: I,
    ) -> Mesh<S>
    where
        S: BaseFloat,
        I: IntoIterator<Item = geom::Tri<V>>,
        V: geom::Vertex + IntoVertex<S>,
    {
        let mut vertex_data_ranges = draw::IntermediaryVertexDataRanges::default();
        let mut index_range = 0..0;
        vertex_data_ranges.points.start = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.start = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.start = mesh.vertex_data.tex_coords.len();
        index_range.start = mesh.indices.len();

        let vertices = tris.into_iter()
            .flat_map(geom::Tri::vertices)
            .map(IntoVertex::into_vertex);
        for (i, vertex) in vertices.enumerate() {
            let WithTexCoords {
                tex_coords,
                vertex: WithColor {
                    color,
                    vertex: point,
                },
            } = vertex;
            mesh.vertex_data.points.push(point);
            mesh.vertex_data.colors.push(color);
            mesh.vertex_data.tex_coords.push(tex_coords);
            mesh.indices.push(i);
        }
        vertex_data_ranges.points.end = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.end = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.end = mesh.vertex_data.tex_coords.len();
        index_range.end = mesh.indices.len();
        Mesh::new(vertex_data_ranges, index_range)
    }

    /// Describe the mesh with the given indexed vertices.
    ///
    /// Each trio of `indices` describes a single triangle of `vertices`.
    ///
    /// Each vertex may be any type that may be converted directly into the `draw;;mesh::vertex`
    /// type.
    pub fn indexed<S, V, I>(
        self,
        mesh: &mut draw::IntermediaryMesh<S>,
        vertices: V,
        indices: I,
    ) -> Mesh<S>
    where
        S: BaseFloat,
        V: IntoIterator,
        V::Item: IntoVertex<S>,
        I: IntoIterator<Item = [usize; 3]>,
    {
        let mut vertex_data_ranges = draw::IntermediaryVertexDataRanges::default();
        vertex_data_ranges.points.start = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.start = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.start = mesh.vertex_data.tex_coords.len();
        for vertex in vertices {
            let WithTexCoords {
                tex_coords,
                vertex: WithColor {
                    color,
                    vertex: point,
                },
            } = vertex.into_vertex();
            mesh.vertex_data.points.push(point);
            mesh.vertex_data.colors.push(color);
            mesh.vertex_data.tex_coords.push(tex_coords);
        }
        vertex_data_ranges.points.end = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.end = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.end = mesh.vertex_data.tex_coords.len();
        let mut index_range = mesh.indices.len()..mesh.indices.len();
        let iter = FlattenIndices { iter: indices.into_iter(), current: [0; 3], index: 3 };
        mesh.indices.extend(iter);
        index_range.end = mesh.indices.len();
        Mesh::new(vertex_data_ranges, index_range)
    }
}

impl<S> Mesh<S>
where
    S: BaseFloat,
{
    // Initialise a new `Mesh` with its ranges into the intermediary mesh, ready for drawing.
    fn new(
        vertex_data_ranges: draw::IntermediaryVertexDataRanges,
        index_range: ops::Range<usize>,
    ) -> Self {
        let orientation = Default::default();
        let position = Default::default();
        Mesh {
            orientation,
            position,
            vertex_data_ranges,
            index_range,
        }
    }
}

impl<'a, S> Drawing<'a, Vertexless, S>
where
    S: BaseFloat,
{
    /// Describe the mesh with the given sequence of triangles.
    pub fn tris<I, V>(self, tris: I) -> Drawing<'a, Mesh<S>, S>
    where
        S: BaseFloat,
        I: IntoIterator<Item = geom::Tri<V>>,
        V: geom::Vertex + IntoVertex<S>,
    {
        self.map_ty_with_vertices(|ty, mesh| ty.tris(mesh, tris))
    }

    /// Describe the mesh with the given sequence of indexed vertices.
    pub fn indexed<V, I>(self, vertices: V, indices: I) -> Drawing<'a, Mesh<S>, S>
    where
        S: BaseFloat,
        V: IntoIterator,
        V::Item: IntoVertex<S>,
        I: IntoIterator<Item = [usize; 3]>,
    {
        self.map_ty_with_vertices(|ty, mesh| ty.indexed(mesh, vertices, indices))
    }
}

impl<S> IntoDrawn<S> for Vertexless
where
    S: BaseFloat,
{
    type Vertices = iter::Empty<draw::mesh::Vertex<S>>;
    type Indices = iter::Empty<usize>;
    fn into_drawn(self, _draw: Draw<S>) -> Drawn<S, Self::Vertices, Self::Indices> {
        let properties = Default::default();
        let vertices = iter::empty();
        let indices = iter::empty();
        (properties, vertices, indices)
    }
}

impl<S> IntoDrawn<S> for Mesh<S>
where
    S: BaseFloat,
{
    type Vertices = draw::properties::VerticesFromRanges;
    type Indices = draw::properties::IndicesFromRange;
    fn into_drawn(self, _draw: Draw<S>) -> Drawn<S, Self::Vertices, Self::Indices> {
        let Mesh {
            orientation,
            position,
            vertex_data_ranges,
            index_range,
        } = self;

        let dimensions = spatial::dimension::Properties::default();
        let spatial = spatial::Properties { dimensions, orientation, position };
        let vertices = draw::properties::VerticesFromRanges {
            ranges: vertex_data_ranges,
            fill_color: None,
        };
        let indices = draw::properties::IndicesFromRange { range: index_range };
        (spatial, vertices, indices)
    }
}

impl<I> Iterator for FlattenIndices<I>
where
    I: Iterator<Item = [usize; 3]>,
{
    type Item = usize;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.index < self.current.len() {
                let ix = self.current[self.index];
                self.index += 1;
                return Some(ix);
            }
            match self.iter.next() {
                None => return None,
                Some(trio) => {
                    self.current = trio;
                    self.index = 0;
                },
            }
        }
    }
}

impl<S> SetOrientation<S> for Mesh<S> {
    fn properties(&mut self) -> &mut orientation::Properties<S> {
        SetOrientation::properties(&mut self.orientation)
    }
}

impl<S> SetPosition<S> for Mesh<S> {
    fn properties(&mut self) -> &mut position::Properties<S> {
        SetPosition::properties(&mut self.position)
    }
}

impl<S> From<Vertexless> for Primitive<S> {
    fn from(prim: Vertexless) -> Self {
        Primitive::MeshVertexless(prim)
    }
}

impl<S> From<Mesh<S>> for Primitive<S> {
    fn from(prim: Mesh<S>) -> Self {
        Primitive::Mesh(prim)
    }
}

impl<S> Into<Option<Vertexless>> for Primitive<S> {
    fn into(self) -> Option<Vertexless> {
        match self {
            Primitive::MeshVertexless(prim) => Some(prim),
            _ => None,
        }
    }
}

impl<S> Into<Option<Mesh<S>>> for Primitive<S> {
    fn into(self) -> Option<Mesh<S>> {
        match self {
            Primitive::Mesh(prim) => Some(prim),
            _ => None,
        }
    }
}
<commit_msg>Remove unnecessary BaseFloat constraints from draw mesh module<commit_after>use draw::{self, Drawing};
use draw::mesh::vertex::IntoVertex;
use draw::properties::{Draw, Drawn, IntoDrawn, Primitive, SetOrientation, SetPosition};
use draw::properties::spatial::{self, orientation, position};
use geom;
use math::BaseFloat;
use mesh::vertex::{WithColor, WithTexCoords};
use std::{iter, ops};

/// The mesh type prior to being initialised with vertices or indices.
#[derive(Clone, Debug, Default)]
pub struct Vertexless;

/// Properties related to drawing an arbitrary mesh of colours, geometry and texture.
#[derive(Clone, Debug)]
pub struct Mesh<S = geom::DefaultScalar> {
    position: position::Properties<S>,
    orientation: orientation::Properties<S>,
    vertex_data_ranges: draw::IntermediaryVertexDataRanges,
    index_range: ops::Range<usize>,
}

// A simple iterator for flattening a fixed-size array of indices.
struct FlattenIndices<I> {
    iter: I,
    index: usize,
    current: [usize; 3],
}

impl Vertexless {
    /// Describe the mesh with a sequence of triangles.
    ///
    /// Each triangle may be composed of any vertex type that may be converted directly into the
    /// `draw;;mesh::vertex` type.
    pub fn tris<S, I, V>(
        self,
        mesh: &mut draw::IntermediaryMesh<S>,
        tris: I,
    ) -> Mesh<S>
    where
        S: BaseFloat,
        I: IntoIterator<Item = geom::Tri<V>>,
        V: geom::Vertex + IntoVertex<S>,
    {
        let mut vertex_data_ranges = draw::IntermediaryVertexDataRanges::default();
        let mut index_range = 0..0;
        vertex_data_ranges.points.start = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.start = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.start = mesh.vertex_data.tex_coords.len();
        index_range.start = mesh.indices.len();

        let vertices = tris.into_iter()
            .flat_map(geom::Tri::vertices)
            .map(IntoVertex::into_vertex);
        for (i, vertex) in vertices.enumerate() {
            let WithTexCoords {
                tex_coords,
                vertex: WithColor {
                    color,
                    vertex: point,
                },
            } = vertex;
            mesh.vertex_data.points.push(point);
            mesh.vertex_data.colors.push(color);
            mesh.vertex_data.tex_coords.push(tex_coords);
            mesh.indices.push(i);
        }

        vertex_data_ranges.points.end = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.end = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.end = mesh.vertex_data.tex_coords.len();
        index_range.end = mesh.indices.len();
        Mesh::new(vertex_data_ranges, index_range)
    }

    /// Describe the mesh with the given indexed vertices.
    ///
    /// Each trio of `indices` describes a single triangle of `vertices`.
    ///
    /// Each vertex may be any type that may be converted directly into the `draw;;mesh::vertex`
    /// type.
    pub fn indexed<S, V, I>(
        self,
        mesh: &mut draw::IntermediaryMesh<S>,
        vertices: V,
        indices: I,
    ) -> Mesh<S>
    where
        S: BaseFloat,
        V: IntoIterator,
        V::Item: IntoVertex<S>,
        I: IntoIterator<Item = [usize; 3]>,
    {
        let mut vertex_data_ranges = draw::IntermediaryVertexDataRanges::default();
        vertex_data_ranges.points.start = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.start = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.start = mesh.vertex_data.tex_coords.len();
        for vertex in vertices {
            let WithTexCoords {
                tex_coords,
                vertex: WithColor {
                    color,
                    vertex: point,
                },
            } = vertex.into_vertex();
            mesh.vertex_data.points.push(point);
            mesh.vertex_data.colors.push(color);
            mesh.vertex_data.tex_coords.push(tex_coords);
        }
        vertex_data_ranges.points.end = mesh.vertex_data.points.len();
        vertex_data_ranges.colors.end = mesh.vertex_data.colors.len();
        vertex_data_ranges.tex_coords.end = mesh.vertex_data.tex_coords.len();
        let mut index_range = mesh.indices.len()..mesh.indices.len();
        let iter = FlattenIndices { iter: indices.into_iter(), current: [0; 3], index: 3 };
        mesh.indices.extend(iter);
        index_range.end = mesh.indices.len();
        Mesh::new(vertex_data_ranges, index_range)
    }
}

impl<S> Mesh<S>
where
    S: BaseFloat,
{
    // Initialise a new `Mesh` with its ranges into the intermediary mesh, ready for drawing.
    fn new(
        vertex_data_ranges: draw::IntermediaryVertexDataRanges,
        index_range: ops::Range<usize>,
    ) -> Self {
        let orientation = Default::default();
        let position = Default::default();
        Mesh {
            orientation,
            position,
            vertex_data_ranges,
            index_range,
        }
    }
}

impl<'a, S> Drawing<'a, Vertexless, S>
where
    S: BaseFloat,
{
    /// Describe the mesh with the given sequence of triangles.
    pub fn tris<I, V>(self, tris: I) -> Drawing<'a, Mesh<S>, S>
    where
        I: IntoIterator<Item = geom::Tri<V>>,
        V: geom::Vertex + IntoVertex<S>,
    {
        self.map_ty_with_vertices(|ty, mesh| ty.tris(mesh, tris))
    }

    /// Describe the mesh with the given sequence of indexed vertices.
    pub fn indexed<V, I>(self, vertices: V, indices: I) -> Drawing<'a, Mesh<S>, S>
    where
        V: IntoIterator,
        V::Item: IntoVertex<S>,
        I: IntoIterator<Item = [usize; 3]>,
    {
        self.map_ty_with_vertices(|ty, mesh| ty.indexed(mesh, vertices, indices))
    }
}

impl<S> IntoDrawn<S> for Vertexless
where
    S: BaseFloat,
{
    type Vertices = iter::Empty<draw::mesh::Vertex<S>>;
    type Indices = iter::Empty<usize>;
    fn into_drawn(self, _draw: Draw<S>) -> Drawn<S, Self::Vertices, Self::Indices> {
        let properties = Default::default();
        let vertices = iter::empty();
        let indices = iter::empty();
        (properties, vertices, indices)
    }
}

impl<S> IntoDrawn<S> for Mesh<S>
where
    S: BaseFloat,
{
    type Vertices = draw::properties::VerticesFromRanges;
    type Indices = draw::properties::IndicesFromRange;
    fn into_drawn(self, _draw: Draw<S>) -> Drawn<S, Self::Vertices, Self::Indices> {
        let Mesh {
            orientation,
            position,
            vertex_data_ranges,
            index_range,
        } = self;

        let dimensions = spatial::dimension::Properties::default();
        let spatial = spatial::Properties { dimensions, orientation, position };
        let vertices = draw::properties::VerticesFromRanges {
            ranges: vertex_data_ranges,
            fill_color: None,
        };
        let indices = draw::properties::IndicesFromRange { range: index_range };
        (spatial, vertices, indices)
    }
}

impl<I> Iterator for FlattenIndices<I>
where
    I: Iterator<Item = [usize; 3]>,
{
    type Item = usize;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.index < self.current.len() {
                let ix = self.current[self.index];
                self.index += 1;
                return Some(ix);
            }
            match self.iter.next() {
                None => return None,
                Some(trio) => {
                    self.current = trio;
                    self.index = 0;
                },
            }
        }
    }
}

impl<S> SetOrientation<S> for Mesh<S> {
    fn properties(&mut self) -> &mut orientation::Properties<S> {
        SetOrientation::properties(&mut self.orientation)
    }
}

impl<S> SetPosition<S> for Mesh<S> {
    fn properties(&mut self) -> &mut position::Properties<S> {
        SetPosition::properties(&mut self.position)
    }
}

impl<S> From<Vertexless> for Primitive<S> {
    fn from(prim: Vertexless) -> Self {
        Primitive::MeshVertexless(prim)
    }
}

impl<S> From<Mesh<S>> for Primitive<S> {
    fn from(prim: Mesh<S>) -> Self {
        Primitive::Mesh(prim)
    }
}

impl<S> Into<Option<Vertexless>> for Primitive<S> {
    fn into(self) -> Option<Vertexless> {
        match self {
            Primitive::MeshVertexless(prim) => Some(prim),
            _ => None,
        }
    }
}

impl<S> Into<Option<Mesh<S>>> for Primitive<S> {
    fn into(self) -> Option<Mesh<S>> {
        match self {
            Primitive::Mesh(prim) => Some(prim),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//! Grid resize and reflow.

use std::cmp::{min, Ordering};

use crate::index::{Column, Line};
use crate::term::cell::Flags;

use crate::grid::row::Row;
use crate::grid::{Dimensions, Grid, GridCell};

impl<T: GridCell + Default + PartialEq + Copy> Grid<T> {
    /// Resize the grid's width and/or height.
    pub fn resize(&mut self, reflow: bool, lines: Line, cols: Column) {
        match self.lines.cmp(&lines) {
            Ordering::Less => self.grow_lines(lines),
            Ordering::Greater => self.shrink_lines(lines),
            Ordering::Equal => (),
        }

        match self.cols.cmp(&cols) {
            Ordering::Less => self.grow_cols(reflow, cols),
            Ordering::Greater => self.shrink_cols(reflow, cols),
            Ordering::Equal => (),
        }
    }

    /// Add lines to the visible area.
    ///
    /// Alacritty keeps the cursor at the bottom of the terminal as long as there
    /// is scrollback available. Once scrollback is exhausted, new lines are
    /// simply added to the bottom of the screen.
    fn grow_lines(&mut self, new_line_count: Line) {
        let lines_added = new_line_count - self.lines;

        // Need to resize before updating buffer.
        self.raw.grow_visible_lines(new_line_count, Row::new(self.cols, T::default()));
        self.lines = new_line_count;

        let history_size = self.history_size();
        let from_history = min(history_size, lines_added.0);

        // Move existing lines up for every line that couldn't be pulled from history.
        if from_history != lines_added.0 {
            let delta = lines_added - from_history;
            self.scroll_up(&(Line(0)..new_line_count), delta, T::default());
        }

        // Move cursor down for every line pulled from history.
        self.saved_cursor.point.line += from_history;
        self.cursor.point.line += from_history;

        self.display_offset = self.display_offset.saturating_sub(*lines_added);
        self.decrease_scroll_limit(*lines_added);
    }

    /// Remove lines from the visible area.
    ///
    /// The behavior in Terminal.app and iTerm.app is to keep the cursor at the
    /// bottom of the screen. This is achieved by pushing history "out the top"
    /// of the terminal window.
    ///
    /// Alacritty takes the same approach.
    fn shrink_lines(&mut self, target: Line) {
        // Scroll up to keep content inside the window.
        let required_scrolling = (self.cursor.point.line + 1).saturating_sub(target.0);
        if required_scrolling > 0 {
            self.scroll_up(&(Line(0)..self.lines), Line(required_scrolling), T::default());

            // Clamp cursors to the new viewport size.
            self.cursor.point.line = min(self.cursor.point.line, target - 1);
        }

        // Clamp saved cursor, since only primary cursor is scrolled into viewport.
        self.saved_cursor.point.line = min(self.saved_cursor.point.line, target - 1);

        self.raw.rotate((self.lines - target).0 as isize);
        self.raw.shrink_visible_lines(target);
        self.lines = target;
    }

    /// Grow number of columns in each row, reflowing if necessary.
    fn grow_cols(&mut self, reflow: bool, cols: Column) {
        // Check if a row needs to be wrapped.
        let should_reflow = |row: &Row<T>| -> bool {
            let len = Column(row.len());
            reflow && len.0 > 0 && len < cols && row[len - 1].flags().contains(Flags::WRAPLINE)
        };

        self.cols = cols;

        let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
        let mut cursor_line_delta = 0;

        // Remove the linewrap special case, by moving the cursor outside of the grid.
        if self.cursor.input_needs_wrap && reflow {
            self.cursor.input_needs_wrap = false;
            self.cursor.point.col += 1;
        }

        let mut rows = self.raw.take_all();

        for (i, mut row) in rows.drain(..).enumerate().rev() {
            // Check if reflowing should be performed.
            let last_row = match reversed.last_mut() {
                Some(last_row) if should_reflow(last_row) => last_row,
                _ => {
                    reversed.push(row);
                    continue;
                },
            };

            // Remove wrap flag before appending additional cells.
            if let Some(cell) = last_row.last_mut() {
                cell.flags_mut().remove(Flags::WRAPLINE);
            }

            // Remove leading spacers when reflowing wide char to the previous line.
            let mut last_len = last_row.len();
            if last_len >= 1
                && last_row[Column(last_len - 1)].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER)
            {
                last_row.shrink(Column(last_len - 1));
                last_len -= 1;
            }

            // Don't try to pull more cells from the next line than available.
            let mut num_wrapped = cols.0 - last_len;
            let len = min(row.len(), num_wrapped);

            // Insert leading spacer when there's not enough room for reflowing wide char.
            let mut cells = if row[Column(len - 1)].flags().contains(Flags::WIDE_CHAR) {
                num_wrapped -= 1;

                let mut cells = row.front_split_off(len - 1);

                let mut spacer = T::default();
                spacer.flags_mut().insert(Flags::LEADING_WIDE_CHAR_SPACER);
                cells.push(spacer);

                cells
            } else {
                row.front_split_off(len)
            };

            // Add removed cells to previous row and reflow content.
            last_row.append(&mut cells);

            let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
            let mut is_clear = row.is_clear();

            if i == cursor_buffer_line && reflow {
                // Resize cursor's line and reflow the cursor if necessary.
                let mut target = self.cursor.point.sub(cols, num_wrapped);

                // Clamp to the last column, if no content was reflown with the cursor.
                if target.col.0 == 0 {
                    self.cursor.input_needs_wrap = true;
                    target = target.sub(cols, 1);
                }
                self.cursor.point.col = target.col;

                let line_delta = (self.cursor.point.line - target.line).0;
                cursor_line_delta += line_delta;
                is_clear &= line_delta != 0;
            } else if is_clear {
                if i + reversed.len() >= self.lines.0 {
                    // Since we removed a line, rotate down the viewport.
                    self.display_offset = self.display_offset.saturating_sub(1);

                    // Rotate cursor down if content below them was pulled from history.
                    if i < cursor_buffer_line {
                        self.cursor.point.line += 1;
                    }
                }

                // Don't push line into the new buffer.
                continue;
            }

            if let (Some(cell), false) = (last_row.last_mut(), is_clear) {
                // Set wrap flag if next line still has cells.
                cell.flags_mut().insert(Flags::WRAPLINE);
            }

            reversed.push(row);
        }

        // Make sure we have at least the viewport filled.
        if reversed.len() < self.lines.0 {
            let delta = self.lines.0 - reversed.len();
            self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(delta);
            reversed.append(&mut vec![Row::new(cols, T::default()); delta]);
        }

        // Pull content down to put cursor in correct position, or move cursor up if there's no
        // more lines to delete below the cursor.
        if cursor_line_delta != 0 {
            let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
            let available = min(cursor_buffer_line, reversed.len() - self.lines.0);
            let overflow = cursor_line_delta.saturating_sub(available);
            reversed.truncate(reversed.len() + overflow - cursor_line_delta);
            self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(overflow);
        }

        // Reverse iterator and fill all rows that are still too short.
        let mut new_raw = Vec::with_capacity(reversed.len());
        for mut row in reversed.drain(..).rev() {
            if row.len() < cols.0 {
                row.grow(cols, T::default());
            }
            new_raw.push(row);
        }

        self.raw.replace_inner(new_raw);

        // Clamp display offset in case lines above it got merged.
        self.display_offset = min(self.display_offset, self.history_size());
    }

    /// Shrink number of columns in each row, reflowing if necessary.
    fn shrink_cols(&mut self, reflow: bool, cols: Column) {
        self.cols = cols;

        // Remove the linewrap special case, by moving the cursor outside of the grid.
        if self.cursor.input_needs_wrap && reflow {
            self.cursor.input_needs_wrap = false;
            self.cursor.point.col += 1;
        }

        let mut new_raw = Vec::with_capacity(self.raw.len());
        let mut buffered: Option<Vec<T>> = None;

        let mut rows = self.raw.take_all();
        for (i, mut row) in rows.drain(..).enumerate().rev() {
            // Append lines left over from the previous row.
            if let Some(buffered) = buffered.take() {
                // Add a column for every cell added before the cursor, if it goes beyond the new
                // width it is then later reflown.
                let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
                if i == cursor_buffer_line {
                    self.cursor.point.col += buffered.len();
                }

                row.append_front(buffered);
            }

            loop {
                // Remove all cells which require reflowing.
                let mut wrapped = match row.shrink(cols) {
                    Some(wrapped) if reflow => wrapped,
                    _ => {
                        let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
                        if reflow && i == cursor_buffer_line && self.cursor.point.col > cols {
                            // If there are empty cells before the cursor, we assume it is explicit
                            // whitespace and need to wrap it like normal content.
                            Vec::new()
                        } else {
                            // Since it fits, just push the existing line without any reflow.
                            new_raw.push(row);
                            break;
                        }
                    },
                };

                // Insert spacer if a wide char would be wrapped into the last column.
                if row.len() >= cols.0 && row[cols - 1].flags().contains(Flags::WIDE_CHAR) {
                    wrapped.insert(0, row[cols - 1]);

                    let mut spacer = T::default();
                    spacer.flags_mut().insert(Flags::LEADING_WIDE_CHAR_SPACER);
                    row[cols - 1] = spacer;
                }

                // Remove wide char spacer before shrinking.
                let len = wrapped.len();
                if wrapped[len - 1].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER) {
                    if len == 1 {
                        row[cols - 1].flags_mut().insert(Flags::WRAPLINE);
                        new_raw.push(row);
                        break;
                    } else {
                        // Remove the leading spacer from the end of the wrapped row.
                        wrapped[len - 2].flags_mut().insert(Flags::WRAPLINE);
                        wrapped.truncate(len - 1);
                    }
                }

                new_raw.push(row);

                // Set line as wrapped if cells got removed.
                if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) {
                    cell.flags_mut().insert(Flags::WRAPLINE);
                }

                if wrapped
                    .last()
                    .map(|c| c.flags().contains(Flags::WRAPLINE) && i >= 1)
                    .unwrap_or(false)
                    && wrapped.len() < cols.0
                {
                    // Make sure previous wrap flag doesn't linger around.
                    if let Some(cell) = wrapped.last_mut() {
                        cell.flags_mut().remove(Flags::WRAPLINE);
                    }

                    // Add removed cells to start of next row.
                    buffered = Some(wrapped);
                    break;
                } else {
                    // Reflow the cursor if it is on this line beyond the width.
                    let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
                    if cursor_buffer_line == i && self.cursor.point.col >= cols {
                        // Since only a single new line is created, we subtract only `cols` from
                        // the cursor instead of reflowing it completely.
                        self.cursor.point.col -= cols;
                    }

                    // Make sure new row is at least as long as new width.
                    let occ = wrapped.len();
                    if occ < cols.0 {
                        wrapped.append(&mut vec![T::default(); cols.0 - occ]);
                    }
                    row = Row::from_vec(wrapped, occ);
                }
            }
        }

        // Reverse iterator and use it as the new grid storage.
        let mut reversed: Vec<Row<T>> = new_raw.drain(..).rev().collect();
        reversed.truncate(self.max_scroll_limit + self.lines.0);
        self.raw.replace_inner(reversed);

        // Reflow the primary cursor, or clamp it if reflow is disabled.
        if !reflow {
            self.cursor.point.col = min(self.cursor.point.col, cols - 1);
        } else if self.cursor.point.col == cols {
            self.cursor.input_needs_wrap = true;
            self.cursor.point.col -= 1;
        } else {
            self.cursor.point = self.cursor.point.add(cols, 0);
        }

        // Clamp the saved cursor to the grid.
        self.saved_cursor.point.col = min(self.saved_cursor.point.col, cols - 1);
    }
}
<commit_msg>Fix crash on cursor resize<commit_after>//! Grid resize and reflow.

use std::cmp::{min, Ordering};

use crate::index::{Column, Line};
use crate::term::cell::Flags;

use crate::grid::row::Row;
use crate::grid::{Dimensions, Grid, GridCell};

impl<T: GridCell + Default + PartialEq + Copy> Grid<T> {
    /// Resize the grid's width and/or height.
    pub fn resize(&mut self, reflow: bool, lines: Line, cols: Column) {
        match self.lines.cmp(&lines) {
            Ordering::Less => self.grow_lines(lines),
            Ordering::Greater => self.shrink_lines(lines),
            Ordering::Equal => (),
        }

        match self.cols.cmp(&cols) {
            Ordering::Less => self.grow_cols(reflow, cols),
            Ordering::Greater => self.shrink_cols(reflow, cols),
            Ordering::Equal => (),
        }
    }

    /// Add lines to the visible area.
    ///
    /// Alacritty keeps the cursor at the bottom of the terminal as long as there
    /// is scrollback available. Once scrollback is exhausted, new lines are
    /// simply added to the bottom of the screen.
    fn grow_lines(&mut self, new_line_count: Line) {
        let lines_added = new_line_count - self.lines;

        // Need to resize before updating buffer.
        self.raw.grow_visible_lines(new_line_count, Row::new(self.cols, T::default()));
        self.lines = new_line_count;

        let history_size = self.history_size();
        let from_history = min(history_size, lines_added.0);

        // Move existing lines up for every line that couldn't be pulled from history.
        if from_history != lines_added.0 {
            let delta = lines_added - from_history;
            self.scroll_up(&(Line(0)..new_line_count), delta, T::default());
        }

        // Move cursor down for every line pulled from history.
        self.saved_cursor.point.line += from_history;
        self.cursor.point.line += from_history;

        self.display_offset = self.display_offset.saturating_sub(*lines_added);
        self.decrease_scroll_limit(*lines_added);
    }

    /// Remove lines from the visible area.
    ///
    /// The behavior in Terminal.app and iTerm.app is to keep the cursor at the
    /// bottom of the screen. This is achieved by pushing history "out the top"
    /// of the terminal window.
    ///
    /// Alacritty takes the same approach.
    fn shrink_lines(&mut self, target: Line) {
        // Scroll up to keep content inside the window.
        let required_scrolling = (self.cursor.point.line + 1).saturating_sub(target.0);
        if required_scrolling > 0 {
            self.scroll_up(&(Line(0)..self.lines), Line(required_scrolling), T::default());

            // Clamp cursors to the new viewport size.
            self.cursor.point.line = min(self.cursor.point.line, target - 1);
        }

        // Clamp saved cursor, since only primary cursor is scrolled into viewport.
        self.saved_cursor.point.line = min(self.saved_cursor.point.line, target - 1);

        self.raw.rotate((self.lines - target).0 as isize);
        self.raw.shrink_visible_lines(target);
        self.lines = target;
    }

    /// Grow number of columns in each row, reflowing if necessary.
    fn grow_cols(&mut self, reflow: bool, cols: Column) {
        // Check if a row needs to be wrapped.
        let should_reflow = |row: &Row<T>| -> bool {
            let len = Column(row.len());
            reflow && len.0 > 0 && len < cols && row[len - 1].flags().contains(Flags::WRAPLINE)
        };

        self.cols = cols;

        let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
        let mut cursor_line_delta = 0;

        // Remove the linewrap special case, by moving the cursor outside of the grid.
        if self.cursor.input_needs_wrap && reflow {
            self.cursor.input_needs_wrap = false;
            self.cursor.point.col += 1;
        }

        let mut rows = self.raw.take_all();

        for (i, mut row) in rows.drain(..).enumerate().rev() {
            // Check if reflowing should be performed.
            let last_row = match reversed.last_mut() {
                Some(last_row) if should_reflow(last_row) => last_row,
                _ => {
                    reversed.push(row);
                    continue;
                },
            };

            // Remove wrap flag before appending additional cells.
            if let Some(cell) = last_row.last_mut() {
                cell.flags_mut().remove(Flags::WRAPLINE);
            }

            // Remove leading spacers when reflowing wide char to the previous line.
            let mut last_len = last_row.len();
            if last_len >= 1
                && last_row[Column(last_len - 1)].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER)
            {
                last_row.shrink(Column(last_len - 1));
                last_len -= 1;
            }

            // Don't try to pull more cells from the next line than available.
            let mut num_wrapped = cols.0 - last_len;
            let len = min(row.len(), num_wrapped);

            // Insert leading spacer when there's not enough room for reflowing wide char.
            let mut cells = if row[Column(len - 1)].flags().contains(Flags::WIDE_CHAR) {
                num_wrapped -= 1;

                let mut cells = row.front_split_off(len - 1);

                let mut spacer = T::default();
                spacer.flags_mut().insert(Flags::LEADING_WIDE_CHAR_SPACER);
                cells.push(spacer);

                cells
            } else {
                row.front_split_off(len)
            };

            // Add removed cells to previous row and reflow content.
            last_row.append(&mut cells);

            let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
            let mut is_clear = row.is_clear();

            if i == cursor_buffer_line && reflow {
                // Resize cursor's line and reflow the cursor if necessary.
                let mut target = self.cursor.point.sub(cols, num_wrapped);

                // Clamp to the last column, if no content was reflown with the cursor.
                if target.col.0 == 0 {
                    self.cursor.input_needs_wrap = true;
                    target = target.sub(cols, 1);
                }
                self.cursor.point.col = target.col;

                let line_delta = (self.cursor.point.line - target.line).0;
                cursor_line_delta += line_delta;
                is_clear &= line_delta != 0;
            } else if is_clear {
                if i + reversed.len() >= self.lines.0 {
                    // Since we removed a line, rotate down the viewport.
                    self.display_offset = self.display_offset.saturating_sub(1);

                    // Rotate cursor down if content below them was pulled from history.
                    if i < cursor_buffer_line {
                        self.cursor.point.line += 1;
                    }
                }

                // Don't push line into the new buffer.
                continue;
            }

            if let (Some(cell), false) = (last_row.last_mut(), is_clear) {
                // Set wrap flag if next line still has cells.
                cell.flags_mut().insert(Flags::WRAPLINE);
            }

            reversed.push(row);
        }

        // Make sure we have at least the viewport filled.
        if reversed.len() < self.lines.0 {
            let delta = self.lines.0 - reversed.len();
            self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(delta);
            reversed.append(&mut vec![Row::new(cols, T::default()); delta]);
        }

        // Pull content down to put cursor in correct position, or move cursor up if there's no
        // more lines to delete below the cursor.
        if cursor_line_delta != 0 {
            let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
            let available = min(cursor_buffer_line, reversed.len() - self.lines.0);
            let overflow = cursor_line_delta.saturating_sub(available);
            reversed.truncate(reversed.len() + overflow - cursor_line_delta);
            self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(overflow);
        }

        // Reverse iterator and fill all rows that are still too short.
        let mut new_raw = Vec::with_capacity(reversed.len());
        for mut row in reversed.drain(..).rev() {
            if row.len() < cols.0 {
                row.grow(cols, T::default());
            }
            new_raw.push(row);
        }

        self.raw.replace_inner(new_raw);

        // Clamp display offset in case lines above it got merged.
        self.display_offset = min(self.display_offset, self.history_size());
    }

    /// Shrink number of columns in each row, reflowing if necessary.
    fn shrink_cols(&mut self, reflow: bool, cols: Column) {
        self.cols = cols;

        // Remove the linewrap special case, by moving the cursor outside of the grid.
        if self.cursor.input_needs_wrap && reflow {
            self.cursor.input_needs_wrap = false;
            self.cursor.point.col += 1;
        }

        let mut new_raw = Vec::with_capacity(self.raw.len());
        let mut buffered: Option<Vec<T>> = None;

        let mut rows = self.raw.take_all();
        for (i, mut row) in rows.drain(..).enumerate().rev() {
            // Append lines left over from the previous row.
            if let Some(buffered) = buffered.take() {
                // Add a column for every cell added before the cursor, if it goes beyond the new
                // width it is then later reflown.
                let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
                if i == cursor_buffer_line {
                    self.cursor.point.col += buffered.len();
                }

                row.append_front(buffered);
            }

            loop {
                // Remove all cells which require reflowing.
                let mut wrapped = match row.shrink(cols) {
                    Some(wrapped) if reflow => wrapped,
                    _ => {
                        let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
                        if reflow && i == cursor_buffer_line && self.cursor.point.col > cols {
                            // If there are empty cells before the cursor, we assume it is explicit
                            // whitespace and need to wrap it like normal content.
                            Vec::new()
                        } else {
                            // Since it fits, just push the existing line without any reflow.
                            new_raw.push(row);
                            break;
                        }
                    },
                };

                // Insert spacer if a wide char would be wrapped into the last column.
                if row.len() >= cols.0 && row[cols - 1].flags().contains(Flags::WIDE_CHAR) {
                    wrapped.insert(0, row[cols - 1]);

                    let mut spacer = T::default();
                    spacer.flags_mut().insert(Flags::LEADING_WIDE_CHAR_SPACER);
                    row[cols - 1] = spacer;
                }

                // Remove wide char spacer before shrinking.
                let len = wrapped.len();
                if len > 0 && wrapped[len - 1].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER) {
                    if len == 1 {
                        row[cols - 1].flags_mut().insert(Flags::WRAPLINE);
                        new_raw.push(row);
                        break;
                    } else {
                        // Remove the leading spacer from the end of the wrapped row.
                        wrapped[len - 2].flags_mut().insert(Flags::WRAPLINE);
                        wrapped.truncate(len - 1);
                    }
                }

                new_raw.push(row);

                // Set line as wrapped if cells got removed.
                if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) {
                    cell.flags_mut().insert(Flags::WRAPLINE);
                }

                if wrapped
                    .last()
                    .map(|c| c.flags().contains(Flags::WRAPLINE) && i >= 1)
                    .unwrap_or(false)
                    && wrapped.len() < cols.0
                {
                    // Make sure previous wrap flag doesn't linger around.
                    if let Some(cell) = wrapped.last_mut() {
                        cell.flags_mut().remove(Flags::WRAPLINE);
                    }

                    // Add removed cells to start of next row.
                    buffered = Some(wrapped);
                    break;
                } else {
                    // Reflow the cursor if it is on this line beyond the width.
                    let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0;
                    if cursor_buffer_line == i && self.cursor.point.col >= cols {
                        // Since only a single new line is created, we subtract only `cols` from
                        // the cursor instead of reflowing it completely.
                        self.cursor.point.col -= cols;
                    }

                    // Make sure new row is at least as long as new width.
                    let occ = wrapped.len();
                    if occ < cols.0 {
                        wrapped.append(&mut vec![T::default(); cols.0 - occ]);
                    }
                    row = Row::from_vec(wrapped, occ);
                }
            }
        }

        // Reverse iterator and use it as the new grid storage.
        let mut reversed: Vec<Row<T>> = new_raw.drain(..).rev().collect();
        reversed.truncate(self.max_scroll_limit + self.lines.0);
        self.raw.replace_inner(reversed);

        // Reflow the primary cursor, or clamp it if reflow is disabled.
        if !reflow {
            self.cursor.point.col = min(self.cursor.point.col, cols - 1);
        } else if self.cursor.point.col == cols {
            self.cursor.input_needs_wrap = true;
            self.cursor.point.col -= 1;
        } else {
            self.cursor.point = self.cursor.point.add(cols, 0);
        }

        // Clamp the saved cursor to the grid.
        self.saved_cursor.point.col = min(self.saved_cursor.point.col, cols - 1);
    }
}
<|endoftext|>