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

//! Processes that are directly spawned by shared mempool runtime initialization

use crate::{
    core_mempool::{CoreMempool, TimelineState},
    counters,
    logging::{LogEntry, LogEvent, LogSchema},
    network::{MempoolNetworkEvents, MempoolSyncMsg},
    shared_mempool::{
        tasks,
        types::{notify_subscribers, ScheduledBroadcast, SharedMempool, SharedMempoolNotification},
    },
    CommitNotification, ConsensusRequest, SubmissionStatus,
};
use ::network::protocols::network::Event;
use anyhow::Result;
use bounded_executor::BoundedExecutor;
use channel::diem_channel;
use diem_config::{config::PeerNetworkId, network_id::NodeNetworkId};
use diem_infallible::Mutex;
use diem_logger::prelude::*;
use diem_trace::prelude::*;
use diem_types::{
    mempool_status::MempoolStatus, on_chain_config::OnChainConfigPayload,
    transaction::SignedTransaction, vm_status::DiscardedVMStatus,
};
use futures::{
    channel::{mpsc, oneshot},
    stream::{select_all, FuturesUnordered},
    StreamExt,
};
use std::{
    ops::Deref,
    sync::Arc,
    time::{Duration, SystemTime},
};
use tokio::{runtime::Handle, time::interval};
use tokio_stream::wrappers::IntervalStream;
use vm_validator::vm_validator::TransactionValidation;

/// Coordinator that handles inbound network events and outbound txn broadcasts.
pub(crate) async fn coordinator<V>(
    mut smp: SharedMempool<V>,
    executor: Handle,
    network_events: Vec<(NodeNetworkId, MempoolNetworkEvents)>,
    mut client_events: mpsc::Receiver<(
        SignedTransaction,
        oneshot::Sender<Result<SubmissionStatus>>,
    )>,
    mut consensus_requests: mpsc::Receiver<ConsensusRequest>,
    mut state_sync_requests: mpsc::Receiver<CommitNotification>,
    mut mempool_reconfig_events: diem_channel::Receiver<(), OnChainConfigPayload>,
) where
    V: TransactionValidation,
{
    info!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Start
    ));
    let smp_events: Vec<_> = network_events
        .into_iter()
        .map(|(network_id, events)| events.map(move |e| (network_id.clone(), e)))
        .collect();
    let mut events = select_all(smp_events).fuse();
    let mempool = smp.mempool.clone();
    let mut scheduled_broadcasts = FuturesUnordered::new();

    // Use a BoundedExecutor to restrict only `workers_available` concurrent
    // worker tasks that can process incoming transactions.
    let workers_available = smp.config.shared_mempool_max_concurrent_inbound_syncs;
    let bounded_executor = BoundedExecutor::new(workers_available, executor.clone());

    loop {
        let _timer = counters::MAIN_LOOP.start_timer();
        ::futures::select! {
            (msg, callback) = client_events.select_next_some() => {
                handle_client_event(&mut smp, &bounded_executor, msg, callback).await;
            },
            msg = consensus_requests.select_next_some() => {
                tasks::process_consensus_request(&mempool, msg).await;
            }
            msg = state_sync_requests.select_next_some() => {
                handle_state_sync_request(&mut smp, msg);
            }
            config_update = mempool_reconfig_events.select_next_some() => {
                handle_mempool_reconfig_event(&mut smp, &bounded_executor, config_update).await;
            },
            (peer, backoff) = scheduled_broadcasts.select_next_some() => {
                tasks::execute_broadcast(peer, backoff, &mut smp, &mut scheduled_broadcasts, executor.clone());
            },
            (network_id, event) = events.select_next_some() => {
                handle_event(&executor, &bounded_executor, &mut scheduled_broadcasts, &mut smp, network_id, event).await;
            },
            complete => break,
        }
    }
    error!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Terminated
    ));
}

async fn handle_client_event<V>(
    smp: &mut SharedMempool<V>,
    bounded_executor: &BoundedExecutor,
    msg: SignedTransaction,
    callback: oneshot::Sender<anyhow::Result<(MempoolStatus, Option<DiscardedVMStatus>)>>,
) where
    V: TransactionValidation,
{
    trace_event!("mempool::client_event", {"txn", msg.sender(), msg.sequence_number()});
    // This timer measures how long it took for the bounded executor to *schedule* the
    // task.
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    // This timer measures how long it took for the task to go from scheduled to started.
    let task_start_timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::START_LABEL])
        .start_timer();
    bounded_executor
        .spawn(tasks::process_client_transaction_submission(
            smp.clone(),
            msg,
            callback,
            task_start_timer,
        ))
        .await;
}

fn handle_state_sync_request<V>(smp: &mut SharedMempool<V>, msg: CommitNotification)
where
    V: TransactionValidation,
{
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::STATE_SYNC_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    tokio::spawn(tasks::process_state_sync_request(smp.mempool.clone(), msg));
}

async fn handle_mempool_reconfig_event<V>(
    smp: &mut SharedMempool<V>,
    bounded_executor: &BoundedExecutor,
    config_update: OnChainConfigPayload,
) where
    V: TransactionValidation,
{
    info!(LogSchema::event_log(
        LogEntry::ReconfigUpdate,
        LogEvent::Received
    ));
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::RECONFIG_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    bounded_executor
        .spawn(tasks::process_config_update(
            config_update,
            smp.validator.clone(),
        ))
        .await;
}

async fn handle_event<V>(
    executor: &Handle,
    bounded_executor: &BoundedExecutor,
    scheduled_broadcasts: &mut FuturesUnordered<ScheduledBroadcast>,
    smp: &mut SharedMempool<V>,
    network_id: NodeNetworkId,
    event: Event<MempoolSyncMsg>,
) where
    V: TransactionValidation,
{
    match event {
        Event::NewPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["new_peer".to_string().deref()])
                .inc();
            let origin = metadata.origin;
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            let is_new_peer = smp.peer_manager.add_peer(peer.clone(), origin);
            let is_upstream_peer = smp.peer_manager.is_upstream_peer(&peer, Some(origin));
            debug!(LogSchema::new(LogEntry::NewPeer)
                .peer(&peer)
                .is_upstream_peer(is_upstream_peer));
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
            if is_new_peer && is_upstream_peer {
                tasks::execute_broadcast(peer, false, smp, scheduled_broadcasts, executor.clone());
            }
        }
        Event::LostPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["lost_peer".to_string().deref()])
                .inc();
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            debug!(LogSchema::new(LogEntry::LostPeer)
                .peer(&peer)
                .is_upstream_peer(
                    smp.peer_manager
                        .is_upstream_peer(&peer, Some(metadata.origin))
                ));
            smp.peer_manager.disable_peer(peer);
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
        }
        Event::Message(peer_id, msg) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["message".to_string().deref()])
                .inc();
            match msg {
                MempoolSyncMsg::BroadcastTransactionsRequest {
                    request_id,
                    transactions,
                } => {
                    let smp_clone = smp.clone();
                    let peer = PeerNetworkId(network_id, peer_id);
                    let timeline_state = match smp.peer_manager.is_upstream_peer(&peer, None) {
                        true => TimelineState::NonQualified,
                        false => TimelineState::NotReady,
                    };
                    // This timer measures how long it took for the bounded executor to
                    // *schedule* the task.
                    let _timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::SPAWN_LABEL,
                        ])
                        .start_timer();
                    // This timer measures how long it took for the task to go from scheduled
                    // to started.
                    let task_start_timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::START_LABEL,
                        ])
                        .start_timer();
                    bounded_executor
                        .spawn(tasks::process_transaction_broadcast(
                            smp_clone,
                            transactions,
                            request_id,
                            timeline_state,
                            peer,
                            task_start_timer,
                        ))
                        .await;
                }
                MempoolSyncMsg::BroadcastTransactionsResponse {
                    request_id,
                    retry,
                    backoff,
                } => {
                    let ack_timestamp = SystemTime::now();
                    smp.peer_manager.process_broadcast_ack(
                        PeerNetworkId(network_id, peer_id),
                        request_id,
                        retry,
                        backoff,
                        ack_timestamp,
                    );
                }
            }
        }
        Event::RpcRequest(peer_id, _msg, _res_tx) => {
            counters::UNEXPECTED_NETWORK_MSG_COUNT
                .with_label_values(&[&network_id.network_id().to_string(), &peer_id.to_string()])
                .inc();
            sample!(
                SampleRate::Duration(Duration::from_secs(60)),
                warn!(LogSchema::new(LogEntry::UnexpectedNetworkMsg)
                    .peer(&PeerNetworkId(network_id, peer_id)))
            );
        }
    }
}

/// Garbage collect all expired transactions by SystemTTL.
pub(crate) async fn gc_coordinator(mempool: Arc<Mutex<CoreMempool>>, gc_interval_ms: u64) {
    info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Start));
    let mut interval = IntervalStream::new(interval(Duration::from_millis(gc_interval_ms)));
    while let Some(_interval) = interval.next().await {
        sample!(
            SampleRate::Duration(Duration::from_secs(60)),
            info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Live))
        );
        mempool.lock().gc();
    }

    error!(LogSchema::event_log(
        LogEntry::GCRuntime,
        LogEvent::Terminated
    ));
}

/// Periodically logs a snapshot of transactions in core mempool.
/// In the future we may want an interactive way to directly query mempool's internal state.
/// For now, we will rely on this periodic snapshot to observe the internal state.
pub(crate) async fn snapshot_job(mempool: Arc<Mutex<CoreMempool>>, snapshot_interval_secs: u64) {
    let mut interval = IntervalStream::new(interval(Duration::from_secs(snapshot_interval_secs)));
    while let Some(_interval) = interval.next().await {
        let snapshot = mempool.lock().gen_snapshot();
        debug!(LogSchema::new(LogEntry::MempoolSnapshot).txns(snapshot));
    }
}
<commit_msg>[mempool] Remove redundant string modifiers in metrics<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Processes that are directly spawned by shared mempool runtime initialization

use crate::{
    core_mempool::{CoreMempool, TimelineState},
    counters,
    logging::{LogEntry, LogEvent, LogSchema},
    network::{MempoolNetworkEvents, MempoolSyncMsg},
    shared_mempool::{
        tasks,
        types::{notify_subscribers, ScheduledBroadcast, SharedMempool, SharedMempoolNotification},
    },
    CommitNotification, ConsensusRequest, SubmissionStatus,
};
use ::network::protocols::network::Event;
use anyhow::Result;
use bounded_executor::BoundedExecutor;
use channel::diem_channel;
use diem_config::{config::PeerNetworkId, network_id::NodeNetworkId};
use diem_infallible::Mutex;
use diem_logger::prelude::*;
use diem_trace::prelude::*;
use diem_types::{
    mempool_status::MempoolStatus, on_chain_config::OnChainConfigPayload,
    transaction::SignedTransaction, vm_status::DiscardedVMStatus,
};
use futures::{
    channel::{mpsc, oneshot},
    stream::{select_all, FuturesUnordered},
    StreamExt,
};
use std::{
    sync::Arc,
    time::{Duration, SystemTime},
};
use tokio::{runtime::Handle, time::interval};
use tokio_stream::wrappers::IntervalStream;
use vm_validator::vm_validator::TransactionValidation;

/// Coordinator that handles inbound network events and outbound txn broadcasts.
pub(crate) async fn coordinator<V>(
    mut smp: SharedMempool<V>,
    executor: Handle,
    network_events: Vec<(NodeNetworkId, MempoolNetworkEvents)>,
    mut client_events: mpsc::Receiver<(
        SignedTransaction,
        oneshot::Sender<Result<SubmissionStatus>>,
    )>,
    mut consensus_requests: mpsc::Receiver<ConsensusRequest>,
    mut state_sync_requests: mpsc::Receiver<CommitNotification>,
    mut mempool_reconfig_events: diem_channel::Receiver<(), OnChainConfigPayload>,
) where
    V: TransactionValidation,
{
    info!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Start
    ));
    let smp_events: Vec<_> = network_events
        .into_iter()
        .map(|(network_id, events)| events.map(move |e| (network_id.clone(), e)))
        .collect();
    let mut events = select_all(smp_events).fuse();
    let mempool = smp.mempool.clone();
    let mut scheduled_broadcasts = FuturesUnordered::new();

    // Use a BoundedExecutor to restrict only `workers_available` concurrent
    // worker tasks that can process incoming transactions.
    let workers_available = smp.config.shared_mempool_max_concurrent_inbound_syncs;
    let bounded_executor = BoundedExecutor::new(workers_available, executor.clone());

    loop {
        let _timer = counters::MAIN_LOOP.start_timer();
        ::futures::select! {
            (msg, callback) = client_events.select_next_some() => {
                handle_client_event(&mut smp, &bounded_executor, msg, callback).await;
            },
            msg = consensus_requests.select_next_some() => {
                tasks::process_consensus_request(&mempool, msg).await;
            }
            msg = state_sync_requests.select_next_some() => {
                handle_state_sync_request(&mut smp, msg);
            }
            config_update = mempool_reconfig_events.select_next_some() => {
                handle_mempool_reconfig_event(&mut smp, &bounded_executor, config_update).await;
            },
            (peer, backoff) = scheduled_broadcasts.select_next_some() => {
                tasks::execute_broadcast(peer, backoff, &mut smp, &mut scheduled_broadcasts, executor.clone());
            },
            (network_id, event) = events.select_next_some() => {
                handle_event(&executor, &bounded_executor, &mut scheduled_broadcasts, &mut smp, network_id, event).await;
            },
            complete => break,
        }
    }
    error!(LogSchema::event_log(
        LogEntry::CoordinatorRuntime,
        LogEvent::Terminated
    ));
}

async fn handle_client_event<V>(
    smp: &mut SharedMempool<V>,
    bounded_executor: &BoundedExecutor,
    msg: SignedTransaction,
    callback: oneshot::Sender<anyhow::Result<(MempoolStatus, Option<DiscardedVMStatus>)>>,
) where
    V: TransactionValidation,
{
    trace_event!("mempool::client_event", {"txn", msg.sender(), msg.sequence_number()});
    // This timer measures how long it took for the bounded executor to *schedule* the
    // task.
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    // This timer measures how long it took for the task to go from scheduled to started.
    let task_start_timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::CLIENT_EVENT_LABEL, counters::START_LABEL])
        .start_timer();
    bounded_executor
        .spawn(tasks::process_client_transaction_submission(
            smp.clone(),
            msg,
            callback,
            task_start_timer,
        ))
        .await;
}

fn handle_state_sync_request<V>(smp: &mut SharedMempool<V>, msg: CommitNotification)
where
    V: TransactionValidation,
{
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::STATE_SYNC_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    tokio::spawn(tasks::process_state_sync_request(smp.mempool.clone(), msg));
}

async fn handle_mempool_reconfig_event<V>(
    smp: &mut SharedMempool<V>,
    bounded_executor: &BoundedExecutor,
    config_update: OnChainConfigPayload,
) where
    V: TransactionValidation,
{
    info!(LogSchema::event_log(
        LogEntry::ReconfigUpdate,
        LogEvent::Received
    ));
    let _timer = counters::TASK_SPAWN_LATENCY
        .with_label_values(&[counters::RECONFIG_EVENT_LABEL, counters::SPAWN_LABEL])
        .start_timer();
    bounded_executor
        .spawn(tasks::process_config_update(
            config_update,
            smp.validator.clone(),
        ))
        .await;
}

async fn handle_event<V>(
    executor: &Handle,
    bounded_executor: &BoundedExecutor,
    scheduled_broadcasts: &mut FuturesUnordered<ScheduledBroadcast>,
    smp: &mut SharedMempool<V>,
    network_id: NodeNetworkId,
    event: Event<MempoolSyncMsg>,
) where
    V: TransactionValidation,
{
    match event {
        Event::NewPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["new_peer"])
                .inc();
            let origin = metadata.origin;
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            let is_new_peer = smp.peer_manager.add_peer(peer.clone(), origin);
            let is_upstream_peer = smp.peer_manager.is_upstream_peer(&peer, Some(origin));
            debug!(LogSchema::new(LogEntry::NewPeer)
                .peer(&peer)
                .is_upstream_peer(is_upstream_peer));
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
            if is_new_peer && is_upstream_peer {
                tasks::execute_broadcast(peer, false, smp, scheduled_broadcasts, executor.clone());
            }
        }
        Event::LostPeer(metadata) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["lost_peer"])
                .inc();
            let peer = PeerNetworkId(network_id, metadata.remote_peer_id);
            debug!(LogSchema::new(LogEntry::LostPeer)
                .peer(&peer)
                .is_upstream_peer(
                    smp.peer_manager
                        .is_upstream_peer(&peer, Some(metadata.origin))
                ));
            smp.peer_manager.disable_peer(peer);
            notify_subscribers(SharedMempoolNotification::PeerStateChange, &smp.subscribers);
        }
        Event::Message(peer_id, msg) => {
            counters::SHARED_MEMPOOL_EVENTS
                .with_label_values(&["message"])
                .inc();
            match msg {
                MempoolSyncMsg::BroadcastTransactionsRequest {
                    request_id,
                    transactions,
                } => {
                    let smp_clone = smp.clone();
                    let peer = PeerNetworkId(network_id, peer_id);
                    let timeline_state = match smp.peer_manager.is_upstream_peer(&peer, None) {
                        true => TimelineState::NonQualified,
                        false => TimelineState::NotReady,
                    };
                    // This timer measures how long it took for the bounded executor to
                    // *schedule* the task.
                    let _timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::SPAWN_LABEL,
                        ])
                        .start_timer();
                    // This timer measures how long it took for the task to go from scheduled
                    // to started.
                    let task_start_timer = counters::TASK_SPAWN_LATENCY
                        .with_label_values(&[
                            counters::PEER_BROADCAST_EVENT_LABEL,
                            counters::START_LABEL,
                        ])
                        .start_timer();
                    bounded_executor
                        .spawn(tasks::process_transaction_broadcast(
                            smp_clone,
                            transactions,
                            request_id,
                            timeline_state,
                            peer,
                            task_start_timer,
                        ))
                        .await;
                }
                MempoolSyncMsg::BroadcastTransactionsResponse {
                    request_id,
                    retry,
                    backoff,
                } => {
                    let ack_timestamp = SystemTime::now();
                    smp.peer_manager.process_broadcast_ack(
                        PeerNetworkId(network_id, peer_id),
                        request_id,
                        retry,
                        backoff,
                        ack_timestamp,
                    );
                }
            }
        }
        Event::RpcRequest(peer_id, _msg, _res_tx) => {
            counters::UNEXPECTED_NETWORK_MSG_COUNT
                .with_label_values(&[&network_id.network_id().to_string(), &peer_id.to_string()])
                .inc();
            sample!(
                SampleRate::Duration(Duration::from_secs(60)),
                warn!(LogSchema::new(LogEntry::UnexpectedNetworkMsg)
                    .peer(&PeerNetworkId(network_id, peer_id)))
            );
        }
    }
}

/// Garbage collect all expired transactions by SystemTTL.
pub(crate) async fn gc_coordinator(mempool: Arc<Mutex<CoreMempool>>, gc_interval_ms: u64) {
    info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Start));
    let mut interval = IntervalStream::new(interval(Duration::from_millis(gc_interval_ms)));
    while let Some(_interval) = interval.next().await {
        sample!(
            SampleRate::Duration(Duration::from_secs(60)),
            info!(LogSchema::event_log(LogEntry::GCRuntime, LogEvent::Live))
        );
        mempool.lock().gc();
    }

    error!(LogSchema::event_log(
        LogEntry::GCRuntime,
        LogEvent::Terminated
    ));
}

/// Periodically logs a snapshot of transactions in core mempool.
/// In the future we may want an interactive way to directly query mempool's internal state.
/// For now, we will rely on this periodic snapshot to observe the internal state.
pub(crate) async fn snapshot_job(mempool: Arc<Mutex<CoreMempool>>, snapshot_interval_secs: u64) {
    let mut interval = IntervalStream::new(interval(Duration::from_secs(snapshot_interval_secs)));
    while let Some(_interval) = interval.next().await {
        let snapshot = mempool.lock().gen_snapshot();
        debug!(LogSchema::new(LogEntry::MempoolSnapshot).txns(snapshot));
    }
}
<|endoftext|>


<commit_before>use super::apple_sdk_base::{opts, Arch};
use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    let base = opts("ios", Arch::Arm64_macabi);
    Target {
        llvm_target: "arm64-apple-ios-macabi".to_string(),
        pointer_width: 64,
        data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        options: TargetOptions {
            features: "+neon,+fp-armv8,+apple-a7".to_string(),
            eliminate_frame_pointer: false,
            max_atomic_width: Some(128),
            unsupported_abis: super::arm_base::unsupported_abis(),
            forces_embed_bitcode: true,
            // Taken from a clang build on Xcode 11.4.1.
            // These arguments are not actually invoked - they just have
            // to look right to pass App Store validation.
            bitcode_llvm_cmdline: "-triple\0\
                arm64-apple-ios-macabi\0\
                -emit-obj\0\
                -disable-llvm-passes\0\
                -target-abi\0\
                darwinpcs\0\
                -Os\0"
                .to_string(),
            ..base
        },
    }
}
<commit_msg>Fixed support for macOS Catalyst for Apple Silicon<commit_after>use super::apple_sdk_base::{opts, Arch};
use crate::spec::{Target, TargetOptions};

pub fn target() -> Target {
    let base = opts("ios", Arch::Arm64_macabi);
    Target {
        llvm_target: "arm64-apple-ios14.0-macabi".to_string(),
        pointer_width: 64,
        data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        options: TargetOptions {
            features: "+neon,+fp-armv8,+apple-a12".to_string(),
            eliminate_frame_pointer: false,
            max_atomic_width: Some(128),
            unsupported_abis: super::arm_base::unsupported_abis(),
            forces_embed_bitcode: true,
            // Taken from a clang build on Xcode 11.4.1.
            // These arguments are not actually invoked - they just have
            // to look right to pass App Store validation.
            bitcode_llvm_cmdline: "-triple\0\
                arm64-apple-ios14.0-macabi\0\
                -emit-obj\0\
                -disable-llvm-passes\0\
                -Os\0"
                .to_string(),
            ..base
        },
    }
}
<|endoftext|>


<commit_before>
// Use this syntax to import more than one type from the same root type
use std::io::{self, Write};

fn fib_recursive(n: u64) -> u64 {
    // Compared to C++, in Rust parenthesis around the expression for if/else
    // statements are not necessary. You can use them but the compiler will
    // warn you that they are unnecessary
    if n == 0 {
        // Numeric literals in Rust can be postfixed with the exact name of the
        // available numeric types, e.g. 1u32 or 2i64, you can also write 1_u32, etc
        // However, this isn't necessary most of the time, the rust compiler is able
        // to infer the type.
        0
    } else if n == 1 {
        // Most things in Rust are expressions, this if/else/else statement is
        // an expression, and we can tell Rust to return it, rather than writing
        // return 1; here, above, and below.
        1
    } else {
        fib_recursive(n - 1) + fib_recursive(n - 2)
    }
}

// A dynamic programming version of fib
fn fib_dp(n: u64) -> u64 {
    if n == 0 || n == 1 {
        n
    } else {
        let mut f1 = 0;
        let mut f2 = 1;
        let mut total = 0;

        // The underscore here tells Rust to throw away the value, I'm not going to use it.
        // On the right half of the 'in', I'm writing a range expression. If you're familiar
        // with python it's like range(2,n+1). The format of x..y is 'half-open', where
        // x is inclusive and y is exclusive
        for _ in 2..(n + 1) {
            total = f1 + f2;
            f1 = f2;
            f2 = total;
        }
        // again, here, we could have written return total; but it's often
        // more concise and idiomatic Rust to just write the value
        total
    }
}

fn main() {
    // "print!" is like "println!" which is used in most examples in the rust
    // book but it doesn't output a newline
    print!("Enter what Fibonacci number you want to compute: ");
    // We need to flush the buffer because print!() does not output a newline
    // character and does not flush; it uses STDOUT which is buffered
    io::stdout().flush().unwrap();

    // ::new() is an associated function implemented on a type, in this case on
    // type String, rather than an instance of String. They are basically
    // equivalent to C++'s static methods
    //
    // Making the variable "mut" (mutable) allows us to change it. In Rust
    // variables are constant (unmutable) by default
    let mut n = String::new();

    // stdin() returns an instance of std::io::Stdin, which represents a handle
    // to the STD output. Equivalent to C++'s std::cin
    //
    // .read_line() is used to read until a newline character is found
    //
    // .expect() checks the return type of .read_line(), which is an enum, and
    // uses the match control operator to check whether the function returned
    // an error enum variant or a success enum variant. On success, it returns
    // the value which the function returns upon success, whereas upon failure
    // it will panic and exit the program after printing the message we pased to
    // it.
    //
    // See enums in the Rust book and std::result, std::result::Result for more
    // information
    io::stdin()
        .read_line(&mut n)
        .expect("Failed to read from STDIN!");

    // In Rust we can perform variable "shadowing". Here the previous
    // declaration of "n" was of type String but now we declare a new variable
    // with name "n" but of numerical type, which is obtained by running the
    // .parse() method. When referring to "n" we will use the latest instance
    // of a type named "n" and not the String instance anymore.
    //
    // .parse() uses the trait FromStr to determine whether
    // a type supports this operation (converting to something from a String)
    let n: u64 = n.trim().parse().expect("Invalid input!");

    println!("The computed value is: {}", fib_recursive(n));
    println!("The computed value is: {}", fib_dp(n));
}
<commit_msg>Add use of `usize` instead of `u64` again<commit_after>
// Use this syntax to import more than one type from the same root type
use std::io::{self, Write};

fn fib_recursive(n: usize) -> usize {
    // Compared to C++, in Rust parenthesis around the expression for if/else
    // statements are not necessary. You can use them but the compiler will
    // warn you that they are unnecessary
    if n == 0 {
        // Numeric literals in Rust can be postfixed with the exact name of the
        // available numeric types, e.g. 1u32 or 2i64, you can also write 1_u32, etc
        // However, this isn't necessary most of the time, the rust compiler is able
        // to infer the type.
        0
    } else if n == 1 {
        // Most things in Rust are expressions, this if/else/else statement is
        // an expression, and we can tell Rust to return it, rather than writing
        // return 1; here, above, and below.
        1
    } else {
        fib_recursive(n - 1) + fib_recursive(n - 2)
    }
}

// A dynamic programming version of fib
fn fib_dp(n: usize) -> usize {
    if n == 0 || n == 1 {
        n
    } else {
        let mut f1 = 0;
        let mut f2 = 1;
        let mut total = 0;

        // The underscore here tells Rust to throw away the value, I'm not going to use it.
        // On the right half of the 'in', I'm writing a range expression. If you're familiar
        // with python it's like range(2,n+1). The format of x..y is 'half-open', where
        // x is inclusive and y is exclusive
        for _ in 2..(n + 1) {
            total = f1 + f2;
            f1 = f2;
            f2 = total;
        }
        // again, here, we could have written return total; but it's often
        // more concise and idiomatic Rust to just write the value
        total
    }
}

fn main() {
    // "print!" is like "println!" which is used in most examples in the rust
    // book but it doesn't output a newline
    print!("Enter what Fibonacci number you want to compute: ");
    // We need to flush the buffer because print!() does not output a newline
    // character and does not flush; it uses STDOUT which is buffered
    io::stdout().flush().unwrap();

    // ::new() is an associated function implemented on a type, in this case on
    // type String, rather than an instance of String. They are basically
    // equivalent to C++'s static methods
    //
    // Making the variable "mut" (mutable) allows us to change it. In Rust
    // variables are constant (unmutable) by default
    let mut n = String::new();

    // stdin() returns an instance of std::io::Stdin, which represents a handle
    // to the STD output. Equivalent to C++'s std::cin
    //
    // .read_line() is used to read until a newline character is found
    //
    // .expect() checks the return type of .read_line(), which is an enum, and
    // uses the match control operator to check whether the function returned
    // an error enum variant or a success enum variant. On success, it returns
    // the value which the function returns upon success, whereas upon failure
    // it will panic and exit the program after printing the message we pased to
    // it.
    //
    // See enums in the Rust book and std::result, std::result::Result for more
    // information
    io::stdin()
        .read_line(&mut n)
        .expect("Failed to read from STDIN!");

    // In Rust we can perform variable "shadowing". Here the previous
    // declaration of "n" was of type String but now we declare a new variable
    // with name "n" but of numerical type, which is obtained by running the
    // .parse() method. When referring to "n" we will use the latest instance
    // of a type named "n" and not the String instance anymore.
    //
    // .parse() uses the trait FromStr to determine whether
    // a type supports this operation (converting to something from a String)
    let n: usize = n.trim().parse().expect("Invalid input!");

    println!("The computed value, computed recursively, is: {}",
             fib_recursive(n));
    println!("The computed value, computed functionally, is: {}", fib_dp(n));
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate sdl2_ttf;
use sdl2::render::{Renderer, TextureQuery, BlendMode};
use sdl2::rect::Rect;
use sdl2::pixels::Color;
use std::vec::Vec;
use std::path::Path;
use font::*;
use std::ops::DerefMut;
use display::{self,Display};
use subtitles::{self,Subtitles};

pub struct Displayer<'a> {
    fonts: FontList,
    renderer: Renderer<'a>,
    #[allow(dead_code)]
    ttf_context: sdl2_ttf::Sdl2TtfContext,
    subtitles:Option<Subtitles>
}

impl<'a> Displayer<'a> {
    pub fn new(mut renderer: Renderer<'a>,subtitles:Option<Subtitles>) -> Result<Displayer<'a>, ()> {
        renderer.set_blend_mode(BlendMode::Blend);
        let ttf_context = sdl2_ttf::init().unwrap();
        let font_list = FontList::new(Path::new("./res/DejaVuSansMono-Bold.ttf"),
                                      &ttf_context)
                            .unwrap();
        let displayer = Displayer {
            fonts: font_list,
            ttf_context: ttf_context,
            renderer: renderer,
            subtitles: subtitles
        };
        Ok(displayer)
    }

    pub fn render_subtitles(&mut self,frame_number:u32){
        let mut text2d_vec = vec![];
        match self.subtitles {
            Some(ref subtitles) => {
                let subtitles = subtitles.get_subtitles();
                let iter = subtitles.iter().enumerate().filter(|&(i,line)|{
                    line.iter().any(|syllabus|{
                        let &(ref syllabus,(frame_begin,frame_end)) = syllabus;
                        (frame_begin <= frame_number) && (frame_number <= frame_end)
                    })
                });
                for (i,line) in iter {
                    let text_pos_y = match i%2 {
                        0 => {display::PosY::FromTopPercent(0.02)},
                        1 => {display::PosY::FromTopPercent(0.12)},
                        _ => unreachable!()
                    };
                    let text_elts = line.iter().fold(vec![],|mut accu_vec,&(ref syllabus,(frame_begin,frame_end))|{
                        if (frame_number < frame_begin){ // not yet

                                let text_2d = display::TextElement {
                                    text:syllabus.clone(),
                                    color:Color::RGBA(128,255,0,255),
                                    outline:Some(Color::RGB(0,0,0)),
                                    shadow:None
                                };
                                accu_vec.push(text_2d);

                        } else if (frame_begin <= frame_number) && (frame_number <= frame_end) {
                            let text_2d = display::TextElement {
                                text:syllabus.clone(),
                                color:Color::RGBA(255,0,0,255),
                                outline:Some(Color::RGB(0,0,0)),
                                shadow:None
                            };
                            accu_vec.push(text_2d);
                        } else {
                            if (accu_vec.is_empty()){
                                let text_2d = display::TextElement {
                                    text:syllabus.clone(),
                                    color:Color::RGBA(128,128,255,255),
                                    outline:Some(Color::RGB(0,0,0)),
                                    shadow:None
                                };
                                accu_vec.push(text_2d);
                            } else {
                                let mut text_2d = accu_vec.last_mut().unwrap();
                                text_2d.text.push_str(&syllabus) ;
                            }
                        }
                        accu_vec
                    });
                    let text_2d = display::Text2D {
                        text:text_elts,
                        size:display::Size::FitPercent(Some(0.95),Some(0.1)),
                        pos:(display::PosX::Centered,text_pos_y),
                        anchor:(0.5,0.0)
                    };
                    text2d_vec.push(text_2d);
                }
            },
            None => {}
        };
        for text2D in text2d_vec.into_iter() {
            text2D.draw(self);
        }
    }

    pub fn display(&mut self, text: &str) {
        let size: f32 = 0.039;
        let window_width = self.renderer.window().unwrap().size().0 ;
        let font_set = self.fonts.get_fittest_font_set(text, (Some(window_width),None),true).unwrap();
        let font = font_set.get_regular_font();
        let font_outline = font_set.get_outline_font();
        let surface = font.render(text)
                          .blended(Color::RGB(180, 180, 180))
                          .unwrap();
        let mut surface_outline = font_outline.render(text)
                                              .blended(Color::RGB(0, 0, 0))
                                              .unwrap();
        let outline_width: u32 = 2;
        let (width, height) = surface_outline.size();
        surface.blit(None,
                     surface_outline.deref_mut(),
                     Some(Rect::new(outline_width as i32,
                                    outline_width as i32,
                                    (width - outline_width),
                                    (height - outline_width)))).expect("Failed to blit texture");
        let mut texture = self.renderer.create_texture_from_surface(&surface_outline).unwrap();
        texture.set_blend_mode(BlendMode::Blend);
        texture.set_alpha_mod(128);
        let TextureQuery { width:texture_width, height:texture_height, format:texture_format,.. } = texture.query();
        self.renderer.copy(&mut texture,
                           None,
                           Some(Rect::new(3, 3, texture_width, texture_height)));
    }

    pub fn example(&mut self) {
        let text_element_1 = display::TextElement {
            text:"S".to_string(),
            color:Color::RGBA(0,0,0,255),
            outline:Some(Color::RGB(255,255,255)),
            shadow:None
        };
        let text_element_2 = display::TextElement {
            text:"L".to_string(),
            color:Color::RGBA(255,255,255,255),
            outline:Some(Color::RGB(0,0,0)),
            shadow:None
        };
        let text_element_3 = display::TextElement {
            text:"T".to_string(),
            color:Color::RGBA(255,0,0,200),
            outline:None,
            shadow:None
        };
        let text_2d : display::Text2D = display::Text2D {
            text:vec![text_element_1,text_element_2,text_element_3],
            size:display::Size::FitPercent(Some(0.9),Some(0.1)),
            pos:(display::PosX::Centered,display::PosY::FromTopPercent(0.50)),
            anchor:(0.5,0.5)
        };
        text_2d.draw(self);
    }

    // width and height must be between 0 and 1
    pub fn sub_screen_dims(&self,width:Option<f32>,height:Option<f32>) -> (Option<u32>,Option<u32>){
        let dims : (u32,u32)= self.renderer.window().unwrap().size();
        (
            width.and_then(|width|{
                Some((width *  (dims.0 as f32)) as u32)
            }) ,
            height.and_then(|height|{
                Some((height *  (dims.1 as f32)) as u32)
            })
        )
    }

    pub fn render(&mut self) {
        self.sdl_renderer_mut().window().unwrap().gl_swap_window();
    }

    pub fn sdl_renderer_mut(&mut self) -> &mut Renderer<'a> {
        &mut self.renderer
    }

    pub fn sdl_renderer(&self) -> &Renderer<'a> {
        &self.renderer
    }

    pub fn fonts(&self) -> &FontList {
        &self.fonts
    }
}
<commit_msg>ttf is being looked in res/<commit_after>extern crate sdl2;
extern crate sdl2_ttf;
use sdl2::render::{Renderer, TextureQuery, BlendMode};
use sdl2::rect::Rect;
use sdl2::pixels::Color;
use std::env;
use std::vec::Vec;
use std::path::Path;
use font::*;
use std::ops::DerefMut;
use display::{self,Display};
use subtitles::{self,Subtitles};

pub struct Displayer<'a> {
    fonts: FontList,
    renderer: Renderer<'a>,
    #[allow(dead_code)]
    ttf_context: sdl2_ttf::Sdl2TtfContext,
    subtitles:Option<Subtitles>
}

impl<'a> Displayer<'a> {
    pub fn new(mut renderer: Renderer<'a>,subtitles:Option<Subtitles>) -> Result<Displayer<'a>, ()> {
        renderer.set_blend_mode(BlendMode::Blend);
        let ttf_context = sdl2_ttf::init().unwrap();
        let mut font_path = env::current_exe().unwrap().parent().unwrap().to_path_buf();
        font_path.push("res/DejaVuSansMono-Bold.ttf");
        let font_path = font_path.as_path();
        let font_list = FontList::new(font_path,
                                      &ttf_context)
                            .unwrap();
        let displayer = Displayer {
            fonts: font_list,
            ttf_context: ttf_context,
            renderer: renderer,
            subtitles: subtitles
        };
        Ok(displayer)
    }

    pub fn render_subtitles(&mut self,frame_number:u32){
        let mut text2d_vec = vec![];
        match self.subtitles {
            Some(ref subtitles) => {
                let subtitles = subtitles.get_subtitles();
                let iter = subtitles.iter().enumerate().filter(|&(i,line)|{
                    line.iter().any(|syllabus|{
                        let &(ref syllabus,(frame_begin,frame_end)) = syllabus;
                        (frame_begin <= frame_number) && (frame_number <= frame_end)
                    })
                });
                for (i,line) in iter {
                    let text_pos_y = match i%2 {
                        0 => {display::PosY::FromTopPercent(0.02)},
                        1 => {display::PosY::FromTopPercent(0.12)},
                        _ => unreachable!()
                    };
                    let text_elts = line.iter().fold(vec![],|mut accu_vec,&(ref syllabus,(frame_begin,frame_end))|{
                        if (frame_number < frame_begin){ // not yet

                                let text_2d = display::TextElement {
                                    text:syllabus.clone(),
                                    color:Color::RGBA(128,255,0,255),
                                    outline:Some(Color::RGB(0,0,0)),
                                    shadow:None
                                };
                                accu_vec.push(text_2d);

                        } else if (frame_begin <= frame_number) && (frame_number <= frame_end) {
                            let text_2d = display::TextElement {
                                text:syllabus.clone(),
                                color:Color::RGBA(255,0,0,255),
                                outline:Some(Color::RGB(0,0,0)),
                                shadow:None
                            };
                            accu_vec.push(text_2d);
                        } else {
                            if (accu_vec.is_empty()){
                                let text_2d = display::TextElement {
                                    text:syllabus.clone(),
                                    color:Color::RGBA(128,128,255,255),
                                    outline:Some(Color::RGB(0,0,0)),
                                    shadow:None
                                };
                                accu_vec.push(text_2d);
                            } else {
                                let mut text_2d = accu_vec.last_mut().unwrap();
                                text_2d.text.push_str(&syllabus) ;
                            }
                        }
                        accu_vec
                    });
                    let text_2d = display::Text2D {
                        text:text_elts,
                        size:display::Size::FitPercent(Some(0.95),Some(0.1)),
                        pos:(display::PosX::Centered,text_pos_y),
                        anchor:(0.5,0.0)
                    };
                    text2d_vec.push(text_2d);
                }
            },
            None => {}
        };
        for text2D in text2d_vec.into_iter() {
            text2D.draw(self);
        }
    }

    pub fn display(&mut self, text: &str) {
        let size: f32 = 0.039;
        let window_width = self.renderer.window().unwrap().size().0 ;
        let font_set = self.fonts.get_fittest_font_set(text, (Some(window_width),None),true).unwrap();
        let font = font_set.get_regular_font();
        let font_outline = font_set.get_outline_font();
        let surface = font.render(text)
                          .blended(Color::RGB(180, 180, 180))
                          .unwrap();
        let mut surface_outline = font_outline.render(text)
                                              .blended(Color::RGB(0, 0, 0))
                                              .unwrap();
        let outline_width: u32 = 2;
        let (width, height) = surface_outline.size();
        surface.blit(None,
                     surface_outline.deref_mut(),
                     Some(Rect::new(outline_width as i32,
                                    outline_width as i32,
                                    (width - outline_width),
                                    (height - outline_width)))).expect("Failed to blit texture");
        let mut texture = self.renderer.create_texture_from_surface(&surface_outline).unwrap();
        texture.set_blend_mode(BlendMode::Blend);
        texture.set_alpha_mod(128);
        let TextureQuery { width:texture_width, height:texture_height, format:texture_format,.. } = texture.query();
        self.renderer.copy(&mut texture,
                           None,
                           Some(Rect::new(3, 3, texture_width, texture_height)));
    }

    pub fn example(&mut self) {
        let text_element_1 = display::TextElement {
            text:"S".to_string(),
            color:Color::RGBA(0,0,0,255),
            outline:Some(Color::RGB(255,255,255)),
            shadow:None
        };
        let text_element_2 = display::TextElement {
            text:"L".to_string(),
            color:Color::RGBA(255,255,255,255),
            outline:Some(Color::RGB(0,0,0)),
            shadow:None
        };
        let text_element_3 = display::TextElement {
            text:"T".to_string(),
            color:Color::RGBA(255,0,0,200),
            outline:None,
            shadow:None
        };
        let text_2d : display::Text2D = display::Text2D {
            text:vec![text_element_1,text_element_2,text_element_3],
            size:display::Size::FitPercent(Some(0.9),Some(0.1)),
            pos:(display::PosX::Centered,display::PosY::FromTopPercent(0.50)),
            anchor:(0.5,0.5)
        };
        text_2d.draw(self);
    }

    // width and height must be between 0 and 1
    pub fn sub_screen_dims(&self,width:Option<f32>,height:Option<f32>) -> (Option<u32>,Option<u32>){
        let dims : (u32,u32)= self.renderer.window().unwrap().size();
        (
            width.and_then(|width|{
                Some((width *  (dims.0 as f32)) as u32)
            }) ,
            height.and_then(|height|{
                Some((height *  (dims.1 as f32)) as u32)
            })
        )
    }

    pub fn render(&mut self) {
        self.sdl_renderer_mut().window().unwrap().gl_swap_window();
    }

    pub fn sdl_renderer_mut(&mut self) -> &mut Renderer<'a> {
        &mut self.renderer
    }

    pub fn sdl_renderer(&self) -> &Renderer<'a> {
        &self.renderer
    }

    pub fn fonts(&self) -> &FontList {
        &self.fonts
    }
}
<|endoftext|>


<commit_before>use ide_db::{
    assists::{AssistId, AssistKind},
    famous_defs::FamousDefs,
};
use syntax::{
    ast::{self, make, Expr, HasArgList},
    AstNode,
};

use crate::{AssistContext, Assists};

// Assist: replace_or_with_or_else
//
// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
//
// ```
// # //- minicore:option
// fn foo() {
//     let a = Some(1);
//     a.unwra$0p_or(2);
// }
// ```
// ->
// ```
// fn foo() {
//     let a = Some(1);
//     a.unwrap_or_else(|| 2);
// }
// ```
pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;

    let kind = is_option_or_result(call.receiver()?, ctx)?;

    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);

    let mut map_or = false;

    let replace = match &*name.text() {
        "unwrap_or" => "unwrap_or_else".to_string(),
        "or" => "or_else".to_string(),
        "ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
        "map_or" => {
            map_or = true;
            "map_or_else".to_string()
        }
        _ => return None,
    };

    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
        [] => make::arg_list(Vec::new()),
        [first] => {
            let param = into_closure(first);
            make::arg_list(vec![param])
        }
        [first, second] if map_or => {
            let param = into_closure(first);
            make::arg_list(vec![param, second.clone()])
        }
        _ => return None,
    };

    acc.add(
        AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
        "Replace unwrap_or or ok_or with lazy version",
        call.syntax().text_range(),
        |builder| {
            builder.replace(name.syntax().text_range(), replace);
            builder.replace_ast(arg_list, arg)
        },
    )
}

fn into_closure(param: &Expr) -> Expr {
    (|| {
        if let ast::Expr::CallExpr(call) = param {
            if call.arg_list()?.args().count() == 0 {
                Some(call.expr()?.clone())
            } else {
                None
            }
        } else {
            None
        }
    })()
    .unwrap_or_else(|| make::expr_closure(None, param.clone()))
}

// Assist: replace_or_else_with_or
//
// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
//
// ```
// # //- minicore:option
// fn foo() {
//     let a = Some(1);
//     a.unwra$0p_or_else(|| 2);
// }
// ```
// ->
// ```
// fn foo() {
//     let a = Some(1);
//     a.unwrap_or(2);
// }
// ```
pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;

    let kind = is_option_or_result(call.receiver()?, ctx)?;

    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);

    let mut map_or = false;
    let replace = match &*name.text() {
        "unwrap_or_else" => "unwrap_or".to_string(),
        "or_else" => "or".to_string(),
        "ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
        "map_or_else" => {
            map_or = true;
            "map_or".to_string()
        }
        _ => return None,
    };

    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
        [] => make::arg_list(Vec::new()),
        [first] => {
            let param = into_call(first);
            make::arg_list(vec![param])
        }
        [first, second] if map_or => {
            let param = into_call(first);
            make::arg_list(vec![param, second.clone()])
        }
        _ => return None,
    };

    acc.add(
        AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
        "Replace unwrap_or_else or ok_or_else with eager version",
        call.syntax().text_range(),
        |builder| {
            builder.replace(name.syntax().text_range(), replace);
            builder.replace_ast(arg_list, arg)
        },
    )
}

fn into_call(param: &Expr) -> Expr {
    (|| {
        if let ast::Expr::ClosureExpr(closure) = param {
            if closure.param_list()?.params().count() == 0 {
                Some(closure.body()?.clone())
            } else {
                None
            }
        } else {
            None
        }
    })()
    .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
}

#[derive(PartialEq, Eq)]
enum Kind {
    Option,
    Result,
}

fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
    let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
    let option_enum =
        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();

    if let Some(option_enum) = option_enum {
        if ty == option_enum {
            return Some(Kind::Option);
        }
    }

    let result_enum =
        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result();

    if let Some(result_enum) = result_enum {
        if ty == result_enum {
            return Some(Kind::Result);
        }
    }

    None
}

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

    use super::*;

    #[test]
    fn replace_or_with_or_else_simple() {
        check_assist(
            replace_or_with_or_else,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or(2);
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or_else(|| 2);
}
"#,
        )
    }

    #[test]
    fn replace_or_with_or_else_call() {
        check_assist(
            replace_or_with_or_else,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or(x());
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or_else(x);
}
"#,
        )
    }

    #[test]
    fn replace_or_with_or_else_block() {
        check_assist(
            replace_or_with_or_else,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or({
        let mut x = bar();
        for i in 0..10 {
            x += i;
        }
        x
    });
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or_else(|| {
        let mut x = bar();
        for i in 0..10 {
            x += i;
        }
        x
    });
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_simple() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or_else(|| 2);
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or(2);
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_call() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or_else(x);
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or(x());
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_result() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: result
fn foo() {
    let foo = Ok(1);
    return foo.unwrap_$0or_else(x);
}
"#,
            r#"
fn foo() {
    let foo = Ok(1);
    return foo.unwrap_or(x());
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_map() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: result
fn foo() {
    let foo = Ok("foo");
    return foo.map$0_or_else(|| 42, |v| v.len());
}
"#,
            r#"
fn foo() {
    let foo = Ok("foo");
    return foo.map_or(42, |v| v.len());
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_not_applicable() {
        check_assist_not_applicable(
            replace_or_else_with_or,
            r#"
fn foo() {
    let foo = Ok(1);
    return foo.unwrap_$0or_else(x);
}
"#,
        )
    }
}
<commit_msg>change title<commit_after>use ide_db::{
    assists::{AssistId, AssistKind},
    famous_defs::FamousDefs,
};
use syntax::{
    ast::{self, make, Expr, HasArgList},
    AstNode,
};

use crate::{AssistContext, Assists};

// Assist: replace_or_with_or_else
//
// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
//
// ```
// # //- minicore:option
// fn foo() {
//     let a = Some(1);
//     a.unwra$0p_or(2);
// }
// ```
// ->
// ```
// fn foo() {
//     let a = Some(1);
//     a.unwrap_or_else(|| 2);
// }
// ```
pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;

    let kind = is_option_or_result(call.receiver()?, ctx)?;

    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);

    let mut map_or = false;

    let replace = match &*name.text() {
        "unwrap_or" => "unwrap_or_else".to_string(),
        "or" => "or_else".to_string(),
        "ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
        "map_or" => {
            map_or = true;
            "map_or_else".to_string()
        }
        _ => return None,
    };

    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
        [] => make::arg_list(Vec::new()),
        [first] => {
            let param = into_closure(first);
            make::arg_list(vec![param])
        }
        [first, second] if map_or => {
            let param = into_closure(first);
            make::arg_list(vec![param, second.clone()])
        }
        _ => return None,
    };

    acc.add(
        AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
        format!("Replace {} with {}", name.text(), replace),
        call.syntax().text_range(),
        |builder| {
            builder.replace(name.syntax().text_range(), replace);
            builder.replace_ast(arg_list, arg)
        },
    )
}

fn into_closure(param: &Expr) -> Expr {
    (|| {
        if let ast::Expr::CallExpr(call) = param {
            if call.arg_list()?.args().count() == 0 {
                Some(call.expr()?.clone())
            } else {
                None
            }
        } else {
            None
        }
    })()
    .unwrap_or_else(|| make::expr_closure(None, param.clone()))
}

// Assist: replace_or_else_with_or
//
// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
//
// ```
// # //- minicore:option
// fn foo() {
//     let a = Some(1);
//     a.unwra$0p_or_else(|| 2);
// }
// ```
// ->
// ```
// fn foo() {
//     let a = Some(1);
//     a.unwrap_or(2);
// }
// ```
pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;

    let kind = is_option_or_result(call.receiver()?, ctx)?;

    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);

    let mut map_or = false;
    let replace = match &*name.text() {
        "unwrap_or_else" => "unwrap_or".to_string(),
        "or_else" => "or".to_string(),
        "ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
        "map_or_else" => {
            map_or = true;
            "map_or".to_string()
        }
        _ => return None,
    };

    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
        [] => make::arg_list(Vec::new()),
        [first] => {
            let param = into_call(first);
            make::arg_list(vec![param])
        }
        [first, second] if map_or => {
            let param = into_call(first);
            make::arg_list(vec![param, second.clone()])
        }
        _ => return None,
    };

    acc.add(
        AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
        format!("Replace {} with {}", name.text(), replace),
        call.syntax().text_range(),
        |builder| {
            builder.replace(name.syntax().text_range(), replace);
            builder.replace_ast(arg_list, arg)
        },
    )
}

fn into_call(param: &Expr) -> Expr {
    (|| {
        if let ast::Expr::ClosureExpr(closure) = param {
            if closure.param_list()?.params().count() == 0 {
                Some(closure.body()?.clone())
            } else {
                None
            }
        } else {
            None
        }
    })()
    .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
}

#[derive(PartialEq, Eq)]
enum Kind {
    Option,
    Result,
}

fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
    let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
    let option_enum =
        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();

    if let Some(option_enum) = option_enum {
        if ty == option_enum {
            return Some(Kind::Option);
        }
    }

    let result_enum =
        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result();

    if let Some(result_enum) = result_enum {
        if ty == result_enum {
            return Some(Kind::Result);
        }
    }

    None
}

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

    use super::*;

    #[test]
    fn replace_or_with_or_else_simple() {
        check_assist(
            replace_or_with_or_else,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or(2);
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or_else(|| 2);
}
"#,
        )
    }

    #[test]
    fn replace_or_with_or_else_call() {
        check_assist(
            replace_or_with_or_else,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or(x());
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or_else(x);
}
"#,
        )
    }

    #[test]
    fn replace_or_with_or_else_block() {
        check_assist(
            replace_or_with_or_else,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or({
        let mut x = bar();
        for i in 0..10 {
            x += i;
        }
        x
    });
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or_else(|| {
        let mut x = bar();
        for i in 0..10 {
            x += i;
        }
        x
    });
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_simple() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or_else(|| 2);
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or(2);
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_call() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: option
fn foo() {
    let foo = Some(1);
    return foo.unwrap_$0or_else(x);
}
"#,
            r#"
fn foo() {
    let foo = Some(1);
    return foo.unwrap_or(x());
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_result() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: result
fn foo() {
    let foo = Ok(1);
    return foo.unwrap_$0or_else(x);
}
"#,
            r#"
fn foo() {
    let foo = Ok(1);
    return foo.unwrap_or(x());
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_map() {
        check_assist(
            replace_or_else_with_or,
            r#"
//- minicore: result
fn foo() {
    let foo = Ok("foo");
    return foo.map$0_or_else(|| 42, |v| v.len());
}
"#,
            r#"
fn foo() {
    let foo = Ok("foo");
    return foo.map_or(42, |v| v.len());
}
"#,
        )
    }

    #[test]
    fn replace_or_else_with_or_not_applicable() {
        check_assist_not_applicable(
            replace_or_else_with_or,
            r#"
fn foo() {
    let foo = Ok(1);
    return foo.unwrap_$0or_else(x);
}
"#,
        )
    }
}
<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;

use self::parser_combinators::{try, between, spaces, parser, many, many1, digit, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;
use std::str::FromStr;
use std::num::FromStrRadix;

fn sint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        optional(satisfy(|c| c == '-'))
            .and(
                (satisfy(|c| c == '0')
                    .and(satisfy(|c| c == 'x' || c == 'X')))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    .map(|x| {
                        isize::from_str_radix(
                            x.iter()
                             .fold(
                                String::new(),
                                |mut s: String, i| { s.push(*i); s })
                             .as_slice(),
                        16).unwrap()
                    })
                .or( many1::<Vec<_>, _>(digit()).map(|x|
                    isize::from_str(x.iter().fold(
                        String::new(), |mut s: String, i| { s.push(*i); s })
                        .as_slice()
                    ).unwrap()
                    )
                )
                )
            .map(|x| {
                if let Some(sign) = x.0 {
                    let mut s = String::new();
                    s.push(sign);
                    s.push('1');
                    x.1 * isize::from_str(s.as_slice()).unwrap()
                } else {
                    x.1
                }
                })
            .skip(not_followed_by(satisfy(|c| c == 'u' || c == 'U' || c == '.')))
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}

fn uint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        (satisfy(|c| c == '0')
            .and(satisfy(|c| c == 'x' || c == 'X')))
            .with(many1::<Vec<_>, _>(hex_digit()))
            .map(|x| usize::from_str_radix(
                    x.iter()
                     .fold(
                        String::new(),
                        |mut s: String, i| { s.push(*i); s })
                     .as_slice(),
                16).unwrap()
            )
        .or( many1::<Vec<_>, _>(digit())
            .map(|x|usize::from_str(x.iter().fold(
                String::new(), |mut s: String, i| { s.push(*i); s })
                .as_slice()
            ).unwrap())
        )
        .skip(satisfy(|c| c == 'u' || c == 'U'))
        .map(|x: usize| NumNode::UIntConst(UIntNode{value: x}))
        .parse_state(input)
}

pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        try(parser(sint_const))
            .or(try(parser(uint_const)))
            .parse_state(input)
}

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let initial = satisfy(|c|
            c.is_alphabetic()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?');
        let subsequent = satisfy(|c|
            c.is_alphanumeric()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?'
                // R6RS 'special subsequent' characters
                || c == '+' || c == '-' || c == '.' || c == '@');
        initial
            .and(many::<Vec<_>, _>(subsequent).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            parser(name)
                .and(many(parser(expr)))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: x.1
                    })
                })
            );
        spaces.clone().with(
            sexpr
                .or(parser(name).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::*;
    use super::parser_combinators::{Parser,parser};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            parser(expr).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

    #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            parser(expr).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

    #[test]
    fn test_parse_sint_pos() {
        assert_eq!(
            parser(number).parse("1234"),
            Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_neg() {
        assert_eq!(
            parser(number).parse("-1234"),
            Ok((NumNode::IntConst(IntNode { value: -1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_hex() {
        assert_eq!(
            parser(number).parse("0x0ff"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
        assert_eq!(
            parser(number).parse("0X0FF"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
    }
    /*
    #[test]
    fn test_parse_sint_bin_upper() {
        assert_eq!(
            parser(number).parse("0B01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
        assert_eq!(
            parser(number).parse("0b01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
    }*/

    #[test]
    fn test_parse_uint() {
        assert_eq!(
            parser(number).parse("1234u"),
            Ok((NumNode::UIntConst(UIntNode { value: 1234usize }), ""))
            );
        assert_eq!(
            parser(number).parse("4321U"),
            Ok((NumNode::UIntConst(UIntNode { value: 4321usize }), ""))
            );
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(
            parser(number).parse("1.0").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("1f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
    }

}
<commit_msg>Stub parser for floats<commit_after>extern crate "parser-combinators" as parser_combinators;

use self::parser_combinators::{try, between, spaces, parser, many, many1, digit, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;
use std::str::FromStr;
use std::num::FromStrRadix;

fn sint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        optional(satisfy(|c| c == '-'))
            .and(
                (satisfy(|c| c == '0')
                    .and(satisfy(|c| c == 'x' || c == 'X')))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    .map(|x| {
                        isize::from_str_radix(
                            x.iter()
                             .fold(
                                String::new(),
                                |mut s: String, i| { s.push(*i); s })
                             .as_slice(),
                        16).unwrap()
                    })
                .or( many1::<Vec<_>, _>(digit()).map(|x|
                    isize::from_str(x.iter().fold(
                        String::new(), |mut s: String, i| { s.push(*i); s })
                        .as_slice()
                    ).unwrap()
                    )
                )
                )
            .map(|x| {
                if let Some(sign) = x.0 {
                    let mut s = String::new();
                    s.push(sign);
                    s.push('1');
                    x.1 * isize::from_str(s.as_slice()).unwrap()
                } else {
                    x.1
                }
                })
            .skip(not_followed_by(satisfy(|c| c == 'u' || c == 'U' || c == '.')))
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}

fn uint_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        (satisfy(|c| c == '0')
            .and(satisfy(|c| c == 'x' || c == 'X')))
            .with(many1::<Vec<_>, _>(hex_digit()))
            .map(|x| usize::from_str_radix(
                    x.iter()
                     .fold(
                        String::new(),
                        |mut s: String, i| { s.push(*i); s })
                     .as_slice(),
                16).unwrap()
            )
        .or( many1::<Vec<_>, _>(digit())
            .map(|x|usize::from_str(x.iter().fold(
                String::new(), |mut s: String, i| { s.push(*i); s })
                .as_slice()
            ).unwrap())
        )
        .skip(satisfy(|c| c == 'u' || c == 'U'))
        .map(|x: usize| NumNode::UIntConst(UIntNode{value: x}))
        .parse_state(input)
}

fn float_const<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        unimplemented!()
}

pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        try(parser(sint_const))
            .or(try(parser(uint_const)))
            .or(try(parser(float_const)))
            .parse_state(input)
}

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let initial = satisfy(|c|
            c.is_alphabetic()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?');
        let subsequent = satisfy(|c|
            c.is_alphanumeric()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?'
                // R6RS 'special subsequent' characters
                || c == '+' || c == '-' || c == '.' || c == '@');
        initial
            .and(many::<Vec<_>, _>(subsequent).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            parser(name)
                .and(many(parser(expr)))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: x.1
                    })
                })
            );
        spaces.clone().with(
            sexpr
                .or(parser(name).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::*;
    use super::parser_combinators::{Parser,parser};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            parser(expr).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

    #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            parser(expr).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

    #[test]
    fn test_parse_sint_pos() {
        assert_eq!(
            parser(number).parse("1234"),
            Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_neg() {
        assert_eq!(
            parser(number).parse("-1234"),
            Ok((NumNode::IntConst(IntNode { value: -1234isize }), ""))
            );
    }

    #[test]
    fn test_parse_sint_hex() {
        assert_eq!(
            parser(number).parse("0x0ff"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
        assert_eq!(
            parser(number).parse("0X0FF"),
            Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
            );
    }
    /*
    #[test]
    fn test_parse_sint_bin_upper() {
        assert_eq!(
            parser(number).parse("0B01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
        assert_eq!(
            parser(number).parse("0b01"),
            Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
            );
    }*/

    #[test]
    fn test_parse_uint() {
        assert_eq!(
            parser(number).parse("1234u"),
            Ok((NumNode::UIntConst(UIntNode { value: 1234usize }), ""))
            );
        assert_eq!(
            parser(number).parse("4321U"),
            Ok((NumNode::UIntConst(UIntNode { value: 4321usize }), ""))
            );
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(
            parser(number).parse("1.0").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("1f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
    }

}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate csv;
extern crate diesel;
extern crate dotenv;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate server;

use chrono::DateTime;
use chrono::offset::Utc;
use diesel::prelude::*;
use diesel::pg::PgConnection;
use dotenv::dotenv;
use server::start_logging;
use server::models::Ad;
use std::env;
use std::io;

#[derive(Debug, Serialize)]
struct Record {
    pub id: String,
    pub html: String,
    pub political: i32,
    pub not_political: i32,
    pub title: String,
    pub message: String,
    pub thumbnail: String,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub lang: String,
    pub images: Option<String>,
    pub impressions: i32,
    pub political_probability: f64,
    pub targeting: Option<String>,
    pub targets: Option<String>,
    pub advertiser: Option<String>,
    pub entities: Option<String>,
    pub page: Option<String>,
}

impl From<Ad> for Record {
    fn from(ad: Ad) -> Self {
        Record {
            targets: serde_json::to_string(&ad.targets).ok(),
            entities: serde_json::to_string(&ad.entities).ok(),
            images: serde_json::to_string(&ad.images).ok(),
            id: ad.id,
            html: ad.html,
            political: ad.political,
            not_political: ad.not_political,
            title: ad.title,
            message: ad.message,
            thumbnail: ad.thumbnail,
            created_at: ad.created_at,
            updated_at: ad.updated_at,
            lang: ad.lang,
            impressions: ad.impressions,
            political_probability: ad.political_probability,
            targeting: ad.targeting,
            advertiser: ad.advertiser,
            page: ad.page,
        }
    }
}

fn main() {
    dotenv().ok();
    start_logging();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let conn = PgConnection::establish(&database_url).unwrap();
    let mut wtr = csv::Writer::from_writer(io::stdout());
    let query = Ad::scoped("en-US");
    let dbads = query.load::<Ad>(&conn).unwrap();
    for ad in dbads {
        wtr.serialize(Record::from(ad)).unwrap();
    }
    wtr.flush().unwrap();
}
<commit_msg>removes Rust archiver<commit_after><|endoftext|>


<commit_before>use sass::value_part::ValuePart;
use sass::op::Op;
use value_tokenizer::ValueTokenizer;

use std::borrow::Cow::Borrowed;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Evaluator<'a> {
    original: &'a str,
    variables: &'a HashMap<String, String>,
    value_stack: Vec<ValuePart<'a>>,
    op_stack: Vec<Op>,
}

impl<'a> Evaluator<'a> {
    pub fn new(original: &'a str, variables: &'a HashMap<String, String>) -> Evaluator<'a> {
        Evaluator {
            original: &original,
            variables: &variables,
            value_stack: Vec::new(),
            op_stack: Vec::new(),
        }
    }

    pub fn evaluate(&mut self) -> String {
        let mut vt = ValueTokenizer::new(self.original);
        let mut last_was_an_operator = true;

        while let Some(part) = vt.next() {
            match part {
                ValuePart::Variable(name) => {
                    match (*self.variables).get(&(*name).to_string()) {
                        Some(ref v) => self.value_stack.push(ValuePart::String(Borrowed(v))),
                        None => self.value_stack.push(ValuePart::String(name)),
                    };
                    last_was_an_operator = false;
                },
                s @ ValuePart::String(..) => {
                    self.value_stack.push(s);
                    last_was_an_operator = false;
                },
                n @ ValuePart::Number(..) => {
                    if last_was_an_operator {
                        self.value_stack.push(n);
                    } else {
                        let list_starter = self.value_stack.pop().expect("No expected list starter on the value stack!");
                        let list_parts = match list_starter {
                            ValuePart::List(mut v) => {
                                v.push(n);
                                v
                            },
                            other => vec![other, n],
                        };
                        self.value_stack.push(ValuePart::List(list_parts));
                    }
                    last_was_an_operator = false;
                },
                ValuePart::Operator(ref o) => {
                    if *o == Op::RightParen {
                        let mut last_operator = self.op_stack.last().expect("Ran out of operators looking for a left paren!").clone();
                        while last_operator != Op::LeftParen {
                            self.math_machine();
                            last_operator = self.op_stack.last().expect("Ran out of operators looking for a left paren!").clone();
                        }
                        self.op_stack.pop();
                    } else if *o == Op::LeftParen {
                        self.op_stack.push(*o);
                    } else {
                        if let Some(&last_operator) = self.op_stack.last() {
                            if last_operator.same_or_greater_precedence(*o) {
                                self.math_machine();
                            }
                        }
                        self.op_stack.push(*o);
                    }
                    last_was_an_operator = true;
                },
                _ => unreachable!(),
            }
        }

        while !self.op_stack.is_empty() {
            self.math_machine();
        }

        // TODO: figure out how to make borrowck like not cloning this, it's cool i swear
        let vs = self.value_stack.clone().into_iter();
        vs.map(|v| v.to_string()).collect::<Vec<_>>().join(" ")
    }

    fn math_machine(&mut self) {
        let op = self.op_stack.pop().expect("No operator on the operator stack!");
        let second = self.value_stack.pop().expect("No second operand on the value stack!");
        let first  = self.value_stack.pop().expect("No first operand on the value stack!");
        self.value_stack.push(op.apply(first, second));
    }
}

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

    #[test]
    fn it_subtitutes_variable_values() {
        let mut vars = HashMap::new();
        vars.insert("$bar".to_string(), "4".to_string());
        vars.insert("$quux".to_string(), "3px 10px".to_string());

        let answer = Evaluator::new("foo $bar 199.82 baz $quux", &vars).evaluate();
        assert_eq!("foo 4 199.82 baz 3px 10px", answer);
    }

    #[test]
    fn it_adds() {
        let answer = Evaluator::new("1 + 2", &HashMap::new()).evaluate();
        assert_eq!("3", answer);
    }

    #[test]
    fn it_doesnt_need_space_around_operators() {
        let answer = Evaluator::new("12*4", &HashMap::new()).evaluate();
        assert_eq!("48", answer);
    }

    #[test]
    fn it_divides_and_adds_with_the_right_precedence() {
        let answer = Evaluator::new("3 + 3/4", &HashMap::new()).evaluate();
        assert_eq!("3.75", answer);
    }

    #[test]
    fn it_gets_the_right_precedence_with_parens() {
        let answer = Evaluator::new("(3 + 3)/4", &HashMap::new()).evaluate();
        assert_eq!("1.5", answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list() {
        let answer = Evaluator::new("2+(3 4)", &HashMap::new()).evaluate();
        assert_eq!("23 4", answer);
    }

    // #[test]
    // fn it_divides_because_parens_and_string_concats_because_list() {
    //     let answer = Evaluator::new("1 + (5/10 2 3)", &HashMap::new()).evaluate();
    //     assert_eq!("10.5 2 3", answer);
    // }
}<commit_msg>Handle a math operation as the first element of a list<commit_after>use sass::value_part::ValuePart;
use sass::op::Op;
use value_tokenizer::ValueTokenizer;

use std::borrow::Cow::Borrowed;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Evaluator<'a> {
    original: &'a str,
    variables: &'a HashMap<String, String>,
    value_stack: Vec<ValuePart<'a>>,
    op_stack: Vec<Op>,
}

impl<'a> Evaluator<'a> {
    pub fn new(original: &'a str, variables: &'a HashMap<String, String>) -> Evaluator<'a> {
        Evaluator {
            original: &original,
            variables: &variables,
            value_stack: Vec::new(),
            op_stack: Vec::new(),
        }
    }

    pub fn evaluate(&mut self) -> String {
        let mut vt = ValueTokenizer::new(self.original);
        let mut last_was_an_operator = true;

        while let Some(part) = vt.next() {
            match part {
                ValuePart::Variable(name) => {
                    match (*self.variables).get(&(*name).to_string()) {
                        Some(ref v) => self.value_stack.push(ValuePart::String(Borrowed(v))),
                        None => self.value_stack.push(ValuePart::String(name)),
                    };
                    last_was_an_operator = false;
                },
                s @ ValuePart::String(..) => {
                    self.value_stack.push(s);
                    last_was_an_operator = false;
                },
                n @ ValuePart::Number(..) => {
                    if last_was_an_operator {
                        self.value_stack.push(n);
                    } else {
                        while !self.op_stack.is_empty() && self.op_stack.last() != Some(&Op::LeftParen) {
                            self.math_machine();
                        }
                        let list_starter = self.value_stack.pop().expect("No expected list starter on the value stack!");
                        let list_parts = match list_starter {
                            ValuePart::List(mut v) => {
                                v.push(n);
                                v
                            },
                            other => vec![other, n],
                        };
                        self.value_stack.push(ValuePart::List(list_parts));
                    }
                    last_was_an_operator = false;
                },
                ValuePart::Operator(ref o) => {
                    if *o == Op::RightParen {
                        let mut last_operator = self.op_stack.last().expect("Ran out of operators looking for a left paren!").clone();
                        while last_operator != Op::LeftParen {
                            self.math_machine();
                            last_operator = self.op_stack.last().expect("Ran out of operators looking for a left paren!").clone();
                        }
                        self.op_stack.pop();
                    } else if *o == Op::LeftParen {
                        self.op_stack.push(*o);
                    } else {
                        if let Some(&last_operator) = self.op_stack.last() {
                            if last_operator.same_or_greater_precedence(*o) {
                                self.math_machine();
                            }
                        }
                        self.op_stack.push(*o);
                    }
                    last_was_an_operator = true;
                },
                _ => unreachable!(),
            }
        }

        while !self.op_stack.is_empty() {
            self.math_machine();
        }

        // TODO: figure out how to make borrowck like not cloning this, it's cool i swear
        let vs = self.value_stack.clone().into_iter();
        vs.map(|v| v.to_string()).collect::<Vec<_>>().join(" ")
    }

    fn math_machine(&mut self) {
        let op = self.op_stack.pop().expect("No operator on the operator stack!");
        let second = self.value_stack.pop().expect("No second operand on the value stack!");
        let first  = self.value_stack.pop().expect("No first operand on the value stack!");
        self.value_stack.push(op.apply(first, second));
    }
}

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

    #[test]
    fn it_subtitutes_variable_values() {
        let mut vars = HashMap::new();
        vars.insert("$bar".to_string(), "4".to_string());
        vars.insert("$quux".to_string(), "3px 10px".to_string());

        let answer = Evaluator::new("foo $bar 199.82 baz $quux", &vars).evaluate();
        assert_eq!("foo 4 199.82 baz 3px 10px", answer);
    }

    #[test]
    fn it_adds() {
        let answer = Evaluator::new("1 + 2", &HashMap::new()).evaluate();
        assert_eq!("3", answer);
    }

    #[test]
    fn it_doesnt_need_space_around_operators() {
        let answer = Evaluator::new("12*4", &HashMap::new()).evaluate();
        assert_eq!("48", answer);
    }

    #[test]
    fn it_divides_and_adds_with_the_right_precedence() {
        let answer = Evaluator::new("3 + 3/4", &HashMap::new()).evaluate();
        assert_eq!("3.75", answer);
    }

    #[test]
    fn it_gets_the_right_precedence_with_parens() {
        let answer = Evaluator::new("(3 + 3)/4", &HashMap::new()).evaluate();
        assert_eq!("1.5", answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list() {
        let answer = Evaluator::new("2+(3 4)", &HashMap::new()).evaluate();
        assert_eq!("23 4", answer);
    }

    #[test]
    fn it_divides_because_parens_and_string_concats_because_list() {
        let answer = Evaluator::new("1 + (5/10 2 3)", &HashMap::new()).evaluate();
        assert_eq!("10.5 2 3", answer);
    }
}<|endoftext|>