<commit_before>use crate::{
    db,
    models::Version,
    render::readme_to_html,
    schema::{crates, readme_renderings, versions},
    Config,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let config = Arc::new(Config::default());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            let config = config.clone();
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(&config, &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(header::CACHE_CONTROL, CACHE_CONTROL_README.parse().unwrap());
                config
                    .uploader
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    config: &Config,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let location = config
        .uploader
        .crate_location(krate_name, &version.num.to_string());

    let response = match client.get(&location).send() {
        Ok(r) => r,
        Err(err) => {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                krate_name, version.num, err
            );
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            krate_name,
            version.num,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Invalid tar archive entries",
            krate_name, version.num
        )
    });
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", krate_name, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        toml::from_str(&contents).unwrap_or_else(|_| {
            panic!(
                "[{}-{}] Syntax error in manifest file",
                krate_name, version.num
            )
        })
    };

    let rendered = {
        let path = format!(
            "{}-{}/{}",
            krate_name, version.num, manifest.package.readme?
        );
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        readme_to_html(
            &contents,
            manifest
                .package
                .readme_file
                .as_ref()
                .map_or("README.md", |e| &**e),
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Deserialize)]
    struct Package {
        readme: Option<String>,
        readme_file: Option<String>,
        repository: Option<String>,
    }

    #[derive(Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    version: &Version,
    krate_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| {
            panic!(
                "[{}-{}] couldn't open file: {}",
                krate_name,
                version.num,
                path.display()
            )
        })
        .unwrap_or_else(|_| {
            panic!(
                "[{}-{}] file is not present: {}",
                krate_name,
                version.num,
                path.display()
            )
        });
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Couldn't read file contents",
            krate_name, version.num
        )
    });
    contents
}
<commit_msg>Auto merge of #3235 - plaets:issue-3194, r=Turbo87<commit_after>use crate::{
    db,
    models::Version,
    render::readme_to_html,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
    Config,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let config = Arc::new(Config::default());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            let config = config.clone();
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(&config, &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(header::CACHE_CONTROL, CACHE_CONTROL_README.parse().unwrap());
                config
                    .uploader
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    config: &Config,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let location = config
        .uploader
        .crate_location(krate_name, &version.num.to_string());

    let location = match config.uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(header::USER_AGENT, USER_AGENT.parse().unwrap());
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                krate_name, version.num, err
            );
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            krate_name,
            version.num,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Invalid tar archive entries",
            krate_name, version.num
        )
    });
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", krate_name, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        toml::from_str(&contents).unwrap_or_else(|_| {
            panic!(
                "[{}-{}] Syntax error in manifest file",
                krate_name, version.num
            )
        })
    };

    let rendered = {
        let path = format!(
            "{}-{}/{}",
            krate_name, version.num, manifest.package.readme?
        );
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        readme_to_html(
            &contents,
            manifest
                .package
                .readme_file
                .as_ref()
                .map_or("README.md", |e| &**e),
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Deserialize)]
    struct Package {
        readme: Option<String>,
        readme_file: Option<String>,
        repository: Option<String>,
    }

    #[derive(Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    version: &Version,
    krate_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| {
            panic!(
                "[{}-{}] couldn't open file: {}",
                krate_name,
                version.num,
                path.display()
            )
        })
        .unwrap_or_else(|_| {
            panic!(
                "[{}-{}] file is not present: {}",
                krate_name,
                version.num,
                path.display()
            )
        });
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Couldn't read file contents",
            krate_name, version.num
        )
    });
    contents
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0
use crate::coordinator::EpochRetrievalRequest;
use crate::{
    coordinator::{CoordinatorMessage, SyncCoordinator, SyncRequest},
    executor_proxy::{ExecutorProxy, ExecutorProxyTrait},
    SynchronizerState,
};
use anyhow::{format_err, Result};
use executor::Executor;
use futures::{
    channel::{mpsc, oneshot},
    future::Future,
    SinkExt,
};
use libra_config::config::{NodeConfig, RoleType, StateSyncConfig};
use libra_mempool::{CommitNotification, CommitResponse};
use libra_types::{
    crypto_proxies::{LedgerInfoWithSignatures, ValidatorChangeProof},
    transaction::Transaction,
    waypoint::Waypoint,
};
use network::validator_network::{StateSynchronizerEvents, StateSynchronizerSender};
use std::{sync::Arc, time::Duration};
use tokio::{
    runtime::{Builder, Runtime},
    time::timeout,
};
use vm_runtime::LibraVM;

pub struct StateSynchronizer {
    _runtime: Runtime,
    coordinator_sender: mpsc::UnboundedSender<CoordinatorMessage>,
}

impl StateSynchronizer {
    /// Setup state synchronizer. spawns coordinator and downloader routines on executor
    pub fn bootstrap(
        network: Vec<(StateSynchronizerSender, StateSynchronizerEvents)>,
        state_sync_to_mempool_sender: mpsc::Sender<CommitNotification>,
        executor: Arc<Executor<LibraVM>>,
        config: &NodeConfig,
    ) -> Self {
        let executor_proxy = ExecutorProxy::new(executor, config);
        Self::bootstrap_with_executor_proxy(
            network,
            state_sync_to_mempool_sender,
            config.base.role,
            config.base.waypoint,
            &config.state_sync,
            executor_proxy,
        )
    }

    pub fn bootstrap_with_executor_proxy<E: ExecutorProxyTrait + 'static>(
        network: Vec<(StateSynchronizerSender, StateSynchronizerEvents)>,
        state_sync_to_mempool_sender: mpsc::Sender<CommitNotification>,
        role: RoleType,
        waypoint: Option<Waypoint>,
        state_sync_config: &StateSyncConfig,
        executor_proxy: E,
    ) -> Self {
        let mut runtime = Builder::new()
            .thread_name("state-sync-")
            .threaded_scheduler()
            .enable_all()
            .build()
            .expect("[state synchronizer] failed to create runtime");

        let (coordinator_sender, coordinator_receiver) = mpsc::unbounded();

        let initial_state = runtime
            .block_on(executor_proxy.get_local_storage_state())
            .expect("[state sync] Start failure: cannot sync with storage.");
        let coordinator = SyncCoordinator::new(
            coordinator_receiver,
            state_sync_to_mempool_sender,
            role,
            waypoint,
            state_sync_config.clone(),
            executor_proxy,
            initial_state,
        );
        runtime.spawn(coordinator.start(network));

        Self {
            _runtime: runtime,
            coordinator_sender,
        }
    }

    pub fn create_client(&self) -> Arc<StateSyncClient> {
        Arc::new(StateSyncClient {
            coordinator_sender: self.coordinator_sender.clone(),
        })
    }

    /// The function returns a future that is fulfilled when the state synchronizer is
    /// caught up with the waypoint specified in the local config.
    pub async fn wait_until_initialized(&self) -> Result<()> {
        let mut sender = self.coordinator_sender.clone();
        let (cb_sender, cb_receiver) = oneshot::channel();
        sender
            .send(CoordinatorMessage::WaitInitialize(cb_sender))
            .await?;
        cb_receiver.await?
    }
}

pub struct StateSyncClient {
    coordinator_sender: mpsc::UnboundedSender<CoordinatorMessage>,
}

impl StateSyncClient {
    /// Sync validator's state to target.
    /// In case of success (`Result::Ok`) the LI of storage is at the given target.
    /// In case of failure (`Result::Error`) the LI of storage remains unchanged, and the validator
    /// can assume there were no modifications to the storage made.
    /// It is up to state synchronizer to decide about the specific criteria for the failure
    /// (e.g., lack of progress with all of the peer validators).
    pub fn sync_to(&self, target: LedgerInfoWithSignatures) -> impl Future<Output = Result<()>> {
        let mut sender = self.coordinator_sender.clone();
        let (callback, cb_receiver) = oneshot::channel();
        let request = SyncRequest { callback, target };
        async move {
            sender.send(CoordinatorMessage::Request(request)).await?;
            cb_receiver.await?
        }
    }

    /// Notifies state synchronizer about new version
    pub fn commit(
        &self,
        // *successfully* committed transactions
        committed_txns: Vec<Transaction>,
    ) -> impl Future<Output = Result<()>> {
        let mut sender = self.coordinator_sender.clone();
        async move {
            let (callback, callback_rcv) = oneshot::channel();
            sender
                .send(CoordinatorMessage::Commit(committed_txns, callback))
                .await?;

            match timeout(Duration::from_secs(1), callback_rcv).await {
                Err(_) => {
                    Err(format_err!("[state sync client] failed to receive commit ACK from state synchronizer on time"))
                }
                Ok(resp) => {
                    match resp?? {
                        CommitResponse { msg } => {
                            if msg != "" {
                                Err(format_err!("[state sync client] commit failed: {:?}", msg))
                            } else {
                                Ok(())
                            }
                        }
                    }
                }
            }
        }
    }

    /// Returns information about StateSynchronizer internal state
    pub fn get_state(&self) -> impl Future<Output = Result<SynchronizerState>> {
        let mut sender = self.coordinator_sender.clone();
        let (cb_sender, cb_receiver) = oneshot::channel();
        async move {
            sender.send(CoordinatorMessage::GetState(cb_sender)).await?;
            let info = cb_receiver.await?;
            Ok(info)
        }
    }

    pub fn get_epoch_proof(
        &self,
        start_epoch: u64,
        end_epoch: u64,
    ) -> impl Future<Output = Result<ValidatorChangeProof>> {
        let mut sender = self.coordinator_sender.clone();
        let (cb_sender, cb_receiver) = oneshot::channel();
        let request = EpochRetrievalRequest {
            start_epoch,
            end_epoch,
            callback: cb_sender,
        };
        async move {
            sender
                .send(CoordinatorMessage::GetEpochProof(request))
                .await?;
            cb_receiver.await?
        }
    }
}
<commit_msg>[clippy] Fix instances of clippy::match_single_binding<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0
use crate::coordinator::EpochRetrievalRequest;
use crate::{
    coordinator::{CoordinatorMessage, SyncCoordinator, SyncRequest},
    executor_proxy::{ExecutorProxy, ExecutorProxyTrait},
    SynchronizerState,
};
use anyhow::{format_err, Result};
use executor::Executor;
use futures::{
    channel::{mpsc, oneshot},
    future::Future,
    SinkExt,
};
use libra_config::config::{NodeConfig, RoleType, StateSyncConfig};
use libra_mempool::{CommitNotification, CommitResponse};
use libra_types::{
    crypto_proxies::{LedgerInfoWithSignatures, ValidatorChangeProof},
    transaction::Transaction,
    waypoint::Waypoint,
};
use network::validator_network::{StateSynchronizerEvents, StateSynchronizerSender};
use std::{sync::Arc, time::Duration};
use tokio::{
    runtime::{Builder, Runtime},
    time::timeout,
};
use vm_runtime::LibraVM;

pub struct StateSynchronizer {
    _runtime: Runtime,
    coordinator_sender: mpsc::UnboundedSender<CoordinatorMessage>,
}

impl StateSynchronizer {
    /// Setup state synchronizer. spawns coordinator and downloader routines on executor
    pub fn bootstrap(
        network: Vec<(StateSynchronizerSender, StateSynchronizerEvents)>,
        state_sync_to_mempool_sender: mpsc::Sender<CommitNotification>,
        executor: Arc<Executor<LibraVM>>,
        config: &NodeConfig,
    ) -> Self {
        let executor_proxy = ExecutorProxy::new(executor, config);
        Self::bootstrap_with_executor_proxy(
            network,
            state_sync_to_mempool_sender,
            config.base.role,
            config.base.waypoint,
            &config.state_sync,
            executor_proxy,
        )
    }

    pub fn bootstrap_with_executor_proxy<E: ExecutorProxyTrait + 'static>(
        network: Vec<(StateSynchronizerSender, StateSynchronizerEvents)>,
        state_sync_to_mempool_sender: mpsc::Sender<CommitNotification>,
        role: RoleType,
        waypoint: Option<Waypoint>,
        state_sync_config: &StateSyncConfig,
        executor_proxy: E,
    ) -> Self {
        let mut runtime = Builder::new()
            .thread_name("state-sync-")
            .threaded_scheduler()
            .enable_all()
            .build()
            .expect("[state synchronizer] failed to create runtime");

        let (coordinator_sender, coordinator_receiver) = mpsc::unbounded();

        let initial_state = runtime
            .block_on(executor_proxy.get_local_storage_state())
            .expect("[state sync] Start failure: cannot sync with storage.");
        let coordinator = SyncCoordinator::new(
            coordinator_receiver,
            state_sync_to_mempool_sender,
            role,
            waypoint,
            state_sync_config.clone(),
            executor_proxy,
            initial_state,
        );
        runtime.spawn(coordinator.start(network));

        Self {
            _runtime: runtime,
            coordinator_sender,
        }
    }

    pub fn create_client(&self) -> Arc<StateSyncClient> {
        Arc::new(StateSyncClient {
            coordinator_sender: self.coordinator_sender.clone(),
        })
    }

    /// The function returns a future that is fulfilled when the state synchronizer is
    /// caught up with the waypoint specified in the local config.
    pub async fn wait_until_initialized(&self) -> Result<()> {
        let mut sender = self.coordinator_sender.clone();
        let (cb_sender, cb_receiver) = oneshot::channel();
        sender
            .send(CoordinatorMessage::WaitInitialize(cb_sender))
            .await?;
        cb_receiver.await?
    }
}

pub struct StateSyncClient {
    coordinator_sender: mpsc::UnboundedSender<CoordinatorMessage>,
}

impl StateSyncClient {
    /// Sync validator's state to target.
    /// In case of success (`Result::Ok`) the LI of storage is at the given target.
    /// In case of failure (`Result::Error`) the LI of storage remains unchanged, and the validator
    /// can assume there were no modifications to the storage made.
    /// It is up to state synchronizer to decide about the specific criteria for the failure
    /// (e.g., lack of progress with all of the peer validators).
    pub fn sync_to(&self, target: LedgerInfoWithSignatures) -> impl Future<Output = Result<()>> {
        let mut sender = self.coordinator_sender.clone();
        let (callback, cb_receiver) = oneshot::channel();
        let request = SyncRequest { callback, target };
        async move {
            sender.send(CoordinatorMessage::Request(request)).await?;
            cb_receiver.await?
        }
    }

    /// Notifies state synchronizer about new version
    pub fn commit(
        &self,
        // *successfully* committed transactions
        committed_txns: Vec<Transaction>,
    ) -> impl Future<Output = Result<()>> {
        let mut sender = self.coordinator_sender.clone();
        async move {
            let (callback, callback_rcv) = oneshot::channel();
            sender
                .send(CoordinatorMessage::Commit(committed_txns, callback))
                .await?;

            match timeout(Duration::from_secs(1), callback_rcv).await {
                Err(_) => {
                    Err(format_err!("[state sync client] failed to receive commit ACK from state synchronizer on time"))
                }
                Ok(resp) => {
                    let CommitResponse { msg } = resp??;
                    if msg != "" {
                        Err(format_err!("[state sync client] commit failed: {:?}", msg))
                    } else {
                        Ok(())
                    }
                }
            }
        }
    }

    /// Returns information about StateSynchronizer internal state
    pub fn get_state(&self) -> impl Future<Output = Result<SynchronizerState>> {
        let mut sender = self.coordinator_sender.clone();
        let (cb_sender, cb_receiver) = oneshot::channel();
        async move {
            sender.send(CoordinatorMessage::GetState(cb_sender)).await?;
            let info = cb_receiver.await?;
            Ok(info)
        }
    }

    pub fn get_epoch_proof(
        &self,
        start_epoch: u64,
        end_epoch: u64,
    ) -> impl Future<Output = Result<ValidatorChangeProof>> {
        let mut sender = self.coordinator_sender.clone();
        let (cb_sender, cb_receiver) = oneshot::channel();
        let request = EpochRetrievalRequest {
            start_epoch,
            end_epoch,
            callback: cb_sender,
        };
        async move {
            sender
                .send(CoordinatorMessage::GetEpochProof(request))
                .await?;
            cb_receiver.await?
        }
    }
}
<|endoftext|>


<commit_before>//! The state object that describes a single segment's information to visualize.

use super::{output_str, output_vec};
use livesplit_core::component::splits::State as SplitsComponentState;
use std::io::Write;
use std::os::raw::c_char;

/// type
pub type OwnedSplitsComponentState = Box<SplitsComponentState>;

/// drop
#[no_mangle]
pub extern "C" fn SplitsComponentState_drop(this: OwnedSplitsComponentState) {
    drop(this);
}

/// Describes whether a more pronounced separator should be shown in front of
/// the last segment provided.
#[no_mangle]
pub extern "C" fn SplitsComponentState_final_separator_shown(this: &SplitsComponentState) -> bool {
    this.show_final_separator
}

/// Returns the amount of segments to visualize.
#[no_mangle]
pub extern "C" fn SplitsComponentState_len(this: &SplitsComponentState) -> usize {
    this.splits.len()
}

/// Returns the amount of icon changes that happened in this state object.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_count(this: &SplitsComponentState) -> usize {
    this.icon_changes.len()
}

/// Accesses the index of the segment of the icon change with the specified
/// index. This is based on the index in the run, not on the index of the
/// SplitState in the State object. The corresponding index is the index field
/// of the SplitState object. You may not provide an out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_segment_index(
    this: &SplitsComponentState,
    icon_change_index: usize,
) -> usize {
    this.icon_changes[icon_change_index].segment_index
}

/// The icon data of the segment of the icon change with the specified index.
/// The buffer may be empty. This indicates that there is no icon. You may not
/// provide an out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_icon_ptr(
    this: &SplitsComponentState,
    icon_change_index: usize,
) -> *const u8 {
    this.icon_changes[icon_change_index].icon.as_ptr()
}

/// The length of the icon data of the segment of the icon change with the
/// specified index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_icon_len(
    this: &SplitsComponentState,
    icon_change_index: usize,
) -> usize {
    this.icon_changes[icon_change_index].icon.len()
}

/// The name of the segment with the specified index. You may not provide an out
/// of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_name(
    this: &SplitsComponentState,
    index: usize,
) -> *const c_char {
    output_str(&this.splits[index].name)
}

/// The amount of columns to visualize for the segment with the specified index.
/// The columns are specified from right to left. You may not provide an out of
/// bounds index. The amount of columns to visualize may differ from segment to
/// segment.
#[no_mangle]
pub extern "C" fn SplitsComponentState_columns_len(
    this: &SplitsComponentState,
    index: usize,
) -> usize {
    this.splits[index].columns.len()
}

/// The column's value to show for the split and column with the specified
/// index. The columns are specified from right to left. You may not provide an
/// out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_column_value(
    this: &SplitsComponentState,
    index: usize,
    column_index: usize,
) -> *const c_char {
    output_str(&this.splits[index].columns[column_index].value)
}

/// The semantic coloring information the column's value carries of the segment
/// and column with the specified index. The columns are specified from right to
/// left. You may not provide an out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_column_semantic_color(
    this: &SplitsComponentState,
    index: usize,
    column_index: usize,
) -> *const c_char {
    output_vec(|f| {
        write!(
            f,
            "{:?}",
            this.splits[index].columns[column_index].semantic_color
        )
        .unwrap()
    })
}

/// Describes if the segment with the specified index is the segment the active
/// attempt is currently on.
#[no_mangle]
pub extern "C" fn SplitsComponentState_is_current_split(
    this: &SplitsComponentState,
    index: usize,
) -> bool {
    this.splits[index].is_current_split
}

/// Returns the label of a specific column
#[no_mangle]
pub extern "C" fn SplitsComponentState_column_label(this: &SplitsComponentState,index: usize,) -> *const c_char {
    let labels = this.column_labels.clone();
    if labels.is_none() {
        return output_str(&"");
    }
    let hthing = &labels.unwrap()[index];
    return output_str(hthing);
}
<commit_msg>Allow identifying if column labels are meant to be shown<commit_after>//! The state object that describes a single segment's information to visualize.

use super::{output_str, output_vec};
use livesplit_core::component::splits::State as SplitsComponentState;
use std::io::Write;
use std::os::raw::c_char;

/// type
pub type OwnedSplitsComponentState = Box<SplitsComponentState>;

/// drop
#[no_mangle]
pub extern "C" fn SplitsComponentState_drop(this: OwnedSplitsComponentState) {
    drop(this);
}

/// Describes whether a more pronounced separator should be shown in front of
/// the last segment provided.
#[no_mangle]
pub extern "C" fn SplitsComponentState_final_separator_shown(this: &SplitsComponentState) -> bool {
    this.show_final_separator
}

/// Returns the amount of segments to visualize.
#[no_mangle]
pub extern "C" fn SplitsComponentState_len(this: &SplitsComponentState) -> usize {
    this.splits.len()
}

/// Returns the amount of icon changes that happened in this state object.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_count(this: &SplitsComponentState) -> usize {
    this.icon_changes.len()
}

/// Accesses the index of the segment of the icon change with the specified
/// index. This is based on the index in the run, not on the index of the
/// SplitState in the State object. The corresponding index is the index field
/// of the SplitState object. You may not provide an out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_segment_index(
    this: &SplitsComponentState,
    icon_change_index: usize,
) -> usize {
    this.icon_changes[icon_change_index].segment_index
}

/// The icon data of the segment of the icon change with the specified index.
/// The buffer may be empty. This indicates that there is no icon. You may not
/// provide an out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_icon_ptr(
    this: &SplitsComponentState,
    icon_change_index: usize,
) -> *const u8 {
    this.icon_changes[icon_change_index].icon.as_ptr()
}

/// The length of the icon data of the segment of the icon change with the
/// specified index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_icon_change_icon_len(
    this: &SplitsComponentState,
    icon_change_index: usize,
) -> usize {
    this.icon_changes[icon_change_index].icon.len()
}

/// The name of the segment with the specified index. You may not provide an out
/// of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_name(
    this: &SplitsComponentState,
    index: usize,
) -> *const c_char {
    output_str(&this.splits[index].name)
}

/// The amount of columns to visualize for the segment with the specified index.
/// The columns are specified from right to left. You may not provide an out of
/// bounds index. The amount of columns to visualize may differ from segment to
/// segment.
#[no_mangle]
pub extern "C" fn SplitsComponentState_columns_len(
    this: &SplitsComponentState,
    index: usize,
) -> usize {
    this.splits[index].columns.len()
}

/// The column's value to show for the split and column with the specified
/// index. The columns are specified from right to left. You may not provide an
/// out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_column_value(
    this: &SplitsComponentState,
    index: usize,
    column_index: usize,
) -> *const c_char {
    output_str(&this.splits[index].columns[column_index].value)
}

/// The semantic coloring information the column's value carries of the segment
/// and column with the specified index. The columns are specified from right to
/// left. You may not provide an out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_column_semantic_color(
    this: &SplitsComponentState,
    index: usize,
    column_index: usize,
) -> *const c_char {
    output_vec(|f| {
        write!(
            f,
            "{:?}",
            this.splits[index].columns[column_index].semantic_color
        )
        .unwrap()
    })
}

/// Describes if the segment with the specified index is the segment the active
/// attempt is currently on.
#[no_mangle]
pub extern "C" fn SplitsComponentState_is_current_split(
    this: &SplitsComponentState,
    index: usize,
) -> bool {
    this.splits[index].is_current_split
}

/// Describes if the columns have labels that are meant to be shown. If this is
/// `false`, no labels are supposed to be visualized.
#[no_mangle]
pub extern "C" fn SplitsComponentState_has_column_labels(this: &SplitsComponentState) -> bool {
    this.column_labels.is_some()
}

/// Returns the label of the column specified. The list is specified from right
/// to left. You may not provide an out of bounds index.
#[no_mangle]
pub extern "C" fn SplitsComponentState_column_label(
    this: &SplitsComponentState,
    index: usize,
) -> *const c_char {
    output_str(if let Some(labels) = &this.column_labels {
        &labels[index]
    } else {
        ""
    })
}
<|endoftext|>


<commit_before>use super::*;

#[derive(Serialize, Deserialize, Debug)]
pub struct Deployment {
    pub spec: DeploymentSpec,
    pub metadata: Metadata,
    pub status: Option<DeploymentStatus>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DeploymentSpec {
    pub min_ready_seconds: Option<u32>,
    pub paused: Option<bool>,
    pub progress_deadline_seconds: Option<u32>,
    pub replicas: Option<u32>,
    pub revision_history_limit: Option<u32>,
    // pub rollback_to: Option<RollbackConfig>,
    // pub selector: Option<LabelSelector>,
    // pub strategy: Option<DeploymentStrategy>,
    // pub template: Option<PodTemplateSpec>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DeploymentStatus {
    pub available_replicas: u32,
    // pub conditions: DeploymentCondition,
    pub observed_generation: u32,
    pub replicas: u32,
    pub unavailable_replicas: u32,
    pub updated_replicas: u32,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct DeploymentList {
    items: Vec<Deployment>,
}

#[derive(Clone, Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DeploymentListQuery {
    #[serde(skip_serializing_if = "Option::is_none")]
    field_selector: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    label_selector: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    resource_version: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    timeout_seconds: Option<String>,
}

impl DeploymentListQuery {
    pub fn field_selector<S: Into<String>>(&self, field_selector: S) -> Self {
        let mut new = self.clone();
        new.field_selector = Some(field_selector.into());
        new
    }
    pub fn label_selector<S: Into<String>>(&self, label_selector: S) -> Self {
        let mut new = self.clone();
        new.label_selector = Some(label_selector.into());
        new
    }
    pub fn resource_version<S: Into<String>>(&self, resource_version: S) -> Self {
        let mut new = self.clone();
        new.resource_version = Some(resource_version.into());
        new
    }
    pub fn timeout_seconds(&self, timeout_seconds: u32) -> Self {
        let mut new = self.clone();
        new.timeout_seconds = Some(timeout_seconds.to_string());
        new
    }
}

impl Deployment {
    pub fn new(name: &str) -> Deployment {
        let spec = DeploymentSpec::default();
        let metadata = Metadata{ name: Some(name.to_owned()), ..Default::default() };
        Deployment { spec, metadata, status: None }
    }
}

impl Resource for Deployment {
    fn kind() -> Kind { Kind::Deployment }
    fn api() -> &'static str {
        "/apis/extensions/v1beta1"
    }
}

impl ListableResource for Deployment {
    type QueryParams = DeploymentListQuery;
    type ListResponse = DeploymentList;
    fn list_items(response: Self::ListResponse) -> Vec<Self> {
        response.items
    }
}<commit_msg>Remove Deployment field that didn't exist<commit_after>use super::*;

#[derive(Serialize, Deserialize, Debug)]
pub struct Deployment {
    pub spec: DeploymentSpec,
    pub metadata: Metadata,
    pub status: Option<DeploymentStatus>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DeploymentSpec {
    pub min_ready_seconds: Option<u32>,
    pub paused: Option<bool>,
    pub progress_deadline_seconds: Option<u32>,
    pub replicas: Option<u32>,
    pub revision_history_limit: Option<u32>,
    // pub rollback_to: Option<RollbackConfig>,
    // pub selector: Option<LabelSelector>,
    // pub strategy: Option<DeploymentStrategy>,
    // pub template: Option<PodTemplateSpec>,
}

#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DeploymentStatus {
    // pub conditions: Option<Vec<DeploymentCondition>>,
    pub observed_generation: u32,
    pub replicas: u32,
    pub unavailable_replicas: u32,
    pub updated_replicas: u32,
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct DeploymentList {
    items: Vec<Deployment>,
}

#[derive(Clone, Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DeploymentListQuery {
    #[serde(skip_serializing_if = "Option::is_none")]
    field_selector: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    label_selector: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    resource_version: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    timeout_seconds: Option<String>,
}

impl DeploymentListQuery {
    pub fn field_selector<S: Into<String>>(&self, field_selector: S) -> Self {
        let mut new = self.clone();
        new.field_selector = Some(field_selector.into());
        new
    }
    pub fn label_selector<S: Into<String>>(&self, label_selector: S) -> Self {
        let mut new = self.clone();
        new.label_selector = Some(label_selector.into());
        new
    }
    pub fn resource_version<S: Into<String>>(&self, resource_version: S) -> Self {
        let mut new = self.clone();
        new.resource_version = Some(resource_version.into());
        new
    }
    pub fn timeout_seconds(&self, timeout_seconds: u32) -> Self {
        let mut new = self.clone();
        new.timeout_seconds = Some(timeout_seconds.to_string());
        new
    }
}

impl Deployment {
    pub fn new(name: &str) -> Deployment {
        let spec = DeploymentSpec::default();
        let metadata = Metadata{ name: Some(name.to_owned()), ..Default::default() };
        Deployment { spec, metadata, status: None }
    }
}

impl Resource for Deployment {
    fn kind() -> Kind { Kind::Deployment }
    fn api() -> &'static str {
        "/apis/extensions/v1beta1"
    }
}

impl ListableResource for Deployment {
    type QueryParams = DeploymentListQuery;
    type ListResponse = DeploymentList;
    fn list_items(response: Self::ListResponse) -> Vec<Self> {
        response.items
    }
}<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS memory allocation library
//!
//! This is in its own crate so it can be used by kernel-space and user-space
//! OS components.
#![crate_name = "alloc"]
#![crate_type = "lib"]

// The compiler needs to be instructed that this crate is an allocator in order
// to realize that when this is linked in another allocator like jemalloc
// should not be linked in
#![cfg_attr( feature = "as_system", feature(allocator) )]
#![cfg_attr( feature = "as_system", allocator )]

#![cfg_attr( feature = "buddy", feature(unique))]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// Allocators are not allowed to depend on the standard library which in turn
// requires an allocator in order to avoid circular dependencies. This crate,
// however, can use all of libcore.
#![no_std]

#![feature( const_fn )]

extern crate memory;

#[cfg(feature = "buddy")]           extern crate sos_intrusive as intrusive;
#[cfg(feature = "buddy_as_system")] extern crate spin;
#[macro_use]                        extern crate log;

/// Trait for something that is like a frame.
///
/// Various allocation strategies use different data structures for
/// representing frames. For example, frames may be stored as frame numbers or
/// as nodes in a linked list. To be `Framesque`, an object need only provide
/// a function to convert the frame data to a pointer to the frame in memory.
pub trait Framesque {
    /// Return a pointer to the frame in memory.
    fn as_ptr(&self) -> *mut u8;
}

#[cfg(feature = "buddy")]
pub mod buddy;

pub mod first_fit;
<commit_msg>[alloc] put FrameAllocator type back into alloc<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS memory allocation library
//!
//! This is in its own crate so it can be used by kernel-space and user-space
//! OS components.
#![crate_name = "alloc"]
#![crate_type = "lib"]

// The compiler needs to be instructed that this crate is an allocator in order
// to realize that when this is linked in another allocator like jemalloc
// should not be linked in
#![cfg_attr( feature = "as_system", feature(allocator) )]
#![cfg_attr( feature = "as_system", allocator )]

#![cfg_attr( feature = "buddy", feature(unique))]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// Allocators are not allowed to depend on the standard library which in turn
// requires an allocator in order to avoid circular dependencies. This crate,
// however, can use all of libcore.
#![no_std]

#![feature( const_fn )]

extern crate memory;
use memory::{PhysicalPage, FrameRange};

use core::ops;

#[cfg(feature = "buddy")]           extern crate sos_intrusive as intrusive;
#[cfg(feature = "buddy_as_system")] extern crate spin;
#[macro_use]                        extern crate log;

/// Trait for something that is like a frame.
///
/// Various allocation strategies use different data structures for
/// representing frames. For example, frames may be stored as frame numbers or
/// as nodes in a linked list. To be `Framesque`, an object need only provide
/// a function to convert the frame data to a pointer to the frame in memory.
pub trait Framesque {
    /// Return a pointer to the frame in memory.
    fn as_ptr(&self) -> *mut u8;
}

/// A borrowed handle on a frame with a specified lifetime.
///
/// This automatically deallocates the frame when the borrow's lifetime
/// ends. It also ensures that the borrow only lives as long as the allocator
/// that provided it, and that the borrow is dropped if the allocator is
/// dropped.
pub struct BorrowedFrame<'a, A>
where A: FrameAllocator
    , A: 'a {
    frame: PhysicalPage
  , allocator: &'a A
}

impl<'a, A> ops::Deref for BorrowedFrame<'a, A>
where A: FrameAllocator
    , A: 'a {
    type Target = PhysicalPage;
    fn deref(&self) ->  &Self::Target { &self.frame }
}

impl<'a, A> ops::DerefMut for BorrowedFrame<'a, A>
where A: FrameAllocator
    , A: 'a {
    fn deref_mut(&mut self) ->  &mut Self::Target { &mut self.frame }
}

impl<'a, A> Drop for BorrowedFrame<'a, A>
where A: FrameAllocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe { self.allocator.deallocate(self.frame) }
    }
}

/// Identical to a `BorrowedFrame` but borrowing a range of `Frame`s.
pub struct BorrowedFrameRange<'a, A>
where A: FrameAllocator
    , A: 'a {
    range: FrameRange
  , allocator: &'a A
}

impl<'a, A> ops::Deref for BorrowedFrameRange<'a, A>
where A: FrameAllocator
    , A: 'a {
    type Target = FrameRange;
    fn deref(&self) -> &Self::Target { &self.range }
}

impl<'a, A> ops::DerefMut for BorrowedFrameRange<'a, A>
where A: FrameAllocator
    , A: 'a {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.range }
}

impl<'a, A> Drop for BorrowedFrameRange<'a, A>
where A: FrameAllocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe { self.allocator.deallocate_range(self.range.clone()) }
    }
}

pub trait FrameAllocator: Sized  {

    unsafe fn allocate(&self) -> Option<PhysicalPage>;
    unsafe fn deallocate(&self, frame: PhysicalPage);

    /// Borrow a `Frame` from this allocator.
    ///e
    /// The `BorrowedFrame` will live as long as this allocator, and will
    /// contain a handle on a `Frame` that will be automatically deallocated
    /// when the `BorrowedFrame` is dropped.
    ///
    /// # Returns:
    /// + `Some(BorrowedFrame)` if there are frames remaining in this
    ///    allocator.
    /// + `None` if the allocator is out of frames.
    fn borrow(&self) -> Option<BorrowedFrame<Self>> {
        unsafe { self.allocate() }
                     .map(|frame| BorrowedFrame { frame: frame
                                                , allocator: self })
    }

    unsafe fn allocate_range(&self, num: usize) -> Option<FrameRange>;
    unsafe fn deallocate_range(&self, range: FrameRange);

    /// Borrow a `FrameRange` from this allocator.
    ///
    /// The `BorrowedFrameRange` will live as long as this allocator, and will
    /// contain a handle on a range of `Frame`s that will be automatically
    /// deallocated when the `BorrowedFrameRange` is dropped.
    ///
    /// # Arguments:
    /// + `num`: The number of frames to allocate.
    ///
    /// # Returns:
    /// + `Some(BorrowedFrameRange)` if there are enough `Frame`s
    ///    remaining in the allocator to fulfill the allocation
    ///    request.
    /// + `None` if there are not enough frames in the allocator to fulfill the
    ///   allocation request.
    fn borrow_range(&self, num: usize) -> Option<BorrowedFrameRange<Self>> {
        unsafe { self.allocate_range(num) }
                     .map(|range| BorrowedFrameRange { range: range
                                                     , allocator: self })
    }

}

#[cfg(feature = "buddy")]
pub mod buddy;

pub mod first_fit;
<|endoftext|>


<commit_before>use super::*;
use std::f32::consts;
use num;
use rand;
use rand::Rng;
use cgmath::InnerSpace;
use app::constants::*;
use app::Event;
use core::clock::*;
use core::geometry::*;
use core::geometry::Transform;
use backend::obj::Transformable;
use backend::world;
use backend::world::agent;
use backend::world::Emission;
use backend::messagebus::{PubSub, Inbox, Whiteboard, ReceiveDrain, Message};

#[derive(Default)]
pub struct PlayerState {
	trigger_held: bool,
	bullet_speed: f32,
	bullet_ready: bool,
	firing_rate: SecondsValue,
	bullet_charge: SecondsValue,
}

pub struct GameSystem {
	timer: SimulationTimer,
	playerstate: PlayerState,
	feeders: Vec<Feeder>,
	inbox: Option<Inbox>,
}

struct Feeder {
	position: Position,
	hourglass: Hourglass,
	to_spawn: usize,
	spawned: usize,
	emission: Emission,
	spin: Spin,
	velocity: f32,
}

impl Feeder where {
	fn new<T>(position: Position, rate: Seconds, emission: Emission, timer: &T) -> Self where T: Timer {
		Feeder {
			position,
			hourglass: Hourglass::new(rate, timer),
			to_spawn: 0,
			spawned: 0,
			emission,
			spin: consts::PI,
			velocity: 5.,
		}
	}
}

impl System for GameSystem {
	fn attach(&mut self, bus: &mut PubSub) {
		self.inbox = Some(bus.subscribe(Box::new(|ev|
			if let &Message::Event(Event::PrimaryFire(_, _)) = ev { true } else { false })));
	}

	fn clear(&mut self) {
		self.playerstate = PlayerState::default();
		self.feeders = Vec::new();
	}

	fn import(&mut self, world: &world::World) {
		let messages = match self.inbox {
			Some(ref m) => m.drain(),
			None => Vec::new(),
		};
		for message in messages {
			match message {
				Message::Event(Event::PrimaryFire(bullet_speed, rate)) => {
					self.primary_fire(bullet_speed, rate);
				}
				_ => {}
			}
		}

		let source = world.feeders();
		// Add missing emitters - deletion not supported
		for i in self.feeders.len()..source.len() {
			let s = &source[i];
			self.feeders.push(Feeder::new(
				s.transform().position,
				s.rate(),
				s.emission(),
				&self.timer,
			));
		}
		for (i, d) in self.feeders.iter_mut().enumerate() {
			d.position = source[i].transform().position;
		}
	}

	fn update(&mut self, _: &world::AgentState, dt: Seconds) {
		let rng = &mut rand::thread_rng();
		self.timer.tick(dt);
		for e in &mut self.feeders {
			e.spawned = e.to_spawn;
		}
		for e in &mut self.feeders {
			if e.hourglass.is_expired(&self.timer) {
				e.hourglass.flip(&self.timer);
				e.to_spawn += 1;
			}
			let tangent = Position::new(-e.position.y, e.position.x).normalize();
			e.position += tangent * rng.next_f32() * dt.get() as f32;
		}
		// Byzantine way of processing trigger presses without trigger releases
		// I should think of something less convoluted
		if !self.playerstate.trigger_held {
			self.playerstate.bullet_charge = BULLET_FULL_CHARGE;
		}
		self.playerstate.bullet_ready = self.playerstate.trigger_held &&
			self.playerstate.bullet_charge >= BULLET_FULL_CHARGE;
		self.playerstate.bullet_charge = if self.playerstate.bullet_ready {
			0.
		} else {
			BULLET_FULL_CHARGE.min(self.playerstate.bullet_charge +
				dt.get() * BULLET_FIRE_RATE * self.playerstate.firing_rate)
		};

		self.playerstate.trigger_held = false;
	}

	fn export(&self, world: &mut world::World, outbox: &Outbox) {
		let rng = &mut rand::thread_rng();
		for e in &self.feeders {
			for i in e.spawned..e.to_spawn {
				let r = match e.emission {
					Emission::Random => rng.next_f32() * 2. * consts::PI,
					Emission::CCW(angle) => angle * i as f32,
					Emission::CW(angle) => -angle * i as f32,
				};
				world.new_resource(
					Transform::new(e.position, r),
					Motion::new(Velocity::new(r.cos(), r.sin()) * e.velocity, e.spin),
				);
			}
		}

		for (i, d) in self.feeders.iter().enumerate() {
			world.feeders_mut()[i].transform_to(Transform::from_position(d.position));
		}

		if self.playerstate.bullet_ready {
			world.primary_fire(outbox, self.playerstate.bullet_speed);
		}
		// if there are no minions, spawn some
		if world.agents(agent::AgentType::Minion).is_empty() {
			world.init_minions();
		}

		if world.agents(agent::AgentType::Player).is_empty() {
			world.init_players();
		}
	}
}

impl Default for GameSystem {
	fn default() -> Self {
		GameSystem {
			timer: SimulationTimer::new(),
			playerstate: PlayerState::default(),
			feeders: Vec::new(),
			inbox: None,
		}
	}
}

impl GameSystem {
	fn primary_fire(&mut self, bullet_speed: f32, firing_rate: SecondsValue) {
		self.playerstate.bullet_speed = bullet_speed;
		self.playerstate.firing_rate = firing_rate;
		self.playerstate.trigger_held = true;
	}
}
<commit_msg>Removed unused use<commit_after>use super::*;
use std::f32::consts;
use rand;
use rand::Rng;
use cgmath::InnerSpace;
use app::constants::*;
use app::Event;
use core::clock::*;
use core::geometry::*;
use core::geometry::Transform;
use backend::obj::Transformable;
use backend::world;
use backend::world::agent;
use backend::world::Emission;
use backend::messagebus::{PubSub, Inbox, Whiteboard, ReceiveDrain, Message};

#[derive(Default)]
pub struct PlayerState {
	trigger_held: bool,
	bullet_speed: f32,
	bullet_ready: bool,
	firing_rate: SecondsValue,
	bullet_charge: SecondsValue,
}

pub struct GameSystem {
	timer: SimulationTimer,
	playerstate: PlayerState,
	feeders: Vec<Feeder>,
	inbox: Option<Inbox>,
}

struct Feeder {
	position: Position,
	hourglass: Hourglass,
	to_spawn: usize,
	spawned: usize,
	emission: Emission,
	spin: Spin,
	velocity: f32,
}

impl Feeder where {
	fn new<T>(position: Position, rate: Seconds, emission: Emission, timer: &T) -> Self where T: Timer {
		Feeder {
			position,
			hourglass: Hourglass::new(rate, timer),
			to_spawn: 0,
			spawned: 0,
			emission,
			spin: consts::PI,
			velocity: 5.,
		}
	}
}

impl System for GameSystem {
	fn attach(&mut self, bus: &mut PubSub) {
		self.inbox = Some(bus.subscribe(Box::new(|ev|
			if let &Message::Event(Event::PrimaryFire(_, _)) = ev { true } else { false })));
	}

	fn clear(&mut self) {
		self.playerstate = PlayerState::default();
		self.feeders = Vec::new();
	}

	fn import(&mut self, world: &world::World) {
		let messages = match self.inbox {
			Some(ref m) => m.drain(),
			None => Vec::new(),
		};
		for message in messages {
			match message {
				Message::Event(Event::PrimaryFire(bullet_speed, rate)) => {
					self.primary_fire(bullet_speed, rate);
				}
				_ => {}
			}
		}

		let source = world.feeders();
		// Add missing emitters - deletion not supported
		for i in self.feeders.len()..source.len() {
			let s = &source[i];
			self.feeders.push(Feeder::new(
				s.transform().position,
				s.rate(),
				s.emission(),
				&self.timer,
			));
		}
		for (i, d) in self.feeders.iter_mut().enumerate() {
			d.position = source[i].transform().position;
		}
	}

	fn update(&mut self, _: &world::AgentState, dt: Seconds) {
		let rng = &mut rand::thread_rng();
		self.timer.tick(dt);
		for e in &mut self.feeders {
			e.spawned = e.to_spawn;
		}
		for e in &mut self.feeders {
			if e.hourglass.is_expired(&self.timer) {
				e.hourglass.flip(&self.timer);
				e.to_spawn += 1;
			}
			let tangent = Position::new(-e.position.y, e.position.x).normalize();
			e.position += tangent * rng.next_f32() * dt.get() as f32;
		}
		// Byzantine way of processing trigger presses without trigger releases
		// I should think of something less convoluted
		if !self.playerstate.trigger_held {
			self.playerstate.bullet_charge = BULLET_FULL_CHARGE;
		}
		self.playerstate.bullet_ready = self.playerstate.trigger_held &&
			self.playerstate.bullet_charge >= BULLET_FULL_CHARGE;
		self.playerstate.bullet_charge = if self.playerstate.bullet_ready {
			0.
		} else {
			BULLET_FULL_CHARGE.min(self.playerstate.bullet_charge +
				dt.get() * BULLET_FIRE_RATE * self.playerstate.firing_rate)
		};

		self.playerstate.trigger_held = false;
	}

	fn export(&self, world: &mut world::World, outbox: &Outbox) {
		let rng = &mut rand::thread_rng();
		for e in &self.feeders {
			for i in e.spawned..e.to_spawn {
				let r = match e.emission {
					Emission::Random => rng.next_f32() * 2. * consts::PI,
					Emission::CCW(angle) => angle * i as f32,
					Emission::CW(angle) => -angle * i as f32,
				};
				world.new_resource(
					Transform::new(e.position, r),
					Motion::new(Velocity::new(r.cos(), r.sin()) * e.velocity, e.spin),
				);
			}
		}

		for (i, d) in self.feeders.iter().enumerate() {
			world.feeders_mut()[i].transform_to(Transform::from_position(d.position));
		}

		if self.playerstate.bullet_ready {
			world.primary_fire(outbox, self.playerstate.bullet_speed);
		}
		// if there are no minions, spawn some
		if world.agents(agent::AgentType::Minion).is_empty() {
			world.init_minions();
		}

		if world.agents(agent::AgentType::Player).is_empty() {
			world.init_players();
		}
	}
}

impl Default for GameSystem {
	fn default() -> Self {
		GameSystem {
			timer: SimulationTimer::new(),
			playerstate: PlayerState::default(),
			feeders: Vec::new(),
			inbox: None,
		}
	}
}

impl GameSystem {
	fn primary_fire(&mut self, bullet_speed: f32, firing_rate: SecondsValue) {
		self.playerstate.bullet_speed = bullet_speed;
		self.playerstate.firing_rate = firing_rate;
		self.playerstate.trigger_held = true;
	}
}
<|endoftext|>


<commit_before>// Queries GitHub and backfills organization IDs for all teams without one
//
// Usage:
//      cargo run --bin backfill-org-ids

#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{db, models::Team, schema::teams};

use diesel::prelude::*;
use regex::Regex;
use reqwest::blocking::{Client, Response};
use serde::Deserialize;
use std::env;

fn main() {
    let conn = db::connect_now().unwrap();
    let client = Client::new();
    backfill_org_ids(&conn, &client);
}

fn backfill_org_ids(conn: &PgConnection, client: &Client) {
    let teams = teams::table
        .filter(teams::org_id.is_null())
        .load::<Team>(conn)
        .unwrap();

    let mut found = 0;
    for team in &teams {
        let option_org_id = query_for_org_id(client, team);
        match option_org_id {
            Some(org_id) => {
                found += 1;
                let update_result = diesel::update(teams::table)
                    .filter(teams::github_id.eq(team.github_id))
                    .set(teams::org_id.eq(org_id))
                    .execute(conn);
                if let Err(msg) = update_result {
                    println!(
                        "problem when updating record for team '{}': {}",
                        team.login, msg
                    );
                }
            }
            None => println!("could not find org id for team '{}'", team.login),
        }
    }

    println!(
        "Recorded organization ids for {} of {} teams",
        found,
        teams.len()
    );
}

fn query_for_org_id(client: &Client, team: &Team) -> Option<i32> {
    query_using_team_id(client, team).or_else(|| query_using_org_name(client, team))
}

fn query_using_team_id(client: &Client, team: &Team) -> Option<i32> {
    // GET https://api.github.com/teams/2874034
    let res = github_http_get(
        client,
        &format!("https://api.github.com/teams/{}", team.github_id),
    )?;

    // HTTP/1.1 404 Not Found
    // link: <https://docs.github.com/changes/2020-01-21-moving-the-team-api-endpoints/>; rel="deprecation"; type="text/html", <https://api.github.com/organizations/14631425/team/2874034>; rel="alternate"
    let link = res.headers().get("Link")?.to_str().ok()?;
    let links = parse_link_header::parse(link).ok()?;
    let re = Regex::new(r"/organizations/(\d+)/team").ok()?;
    let re_captures = re.captures(&links.get(&Some("alternate".into()))?.raw_uri)?;
    let org_id_str = re_captures.get(1)?.as_str();
    let org_id = i32::from_str_radix(&org_id_str, 10).ok()?;

    if org_id == 0 {
        None
    } else {
        Some(org_id)
    }
}

fn query_using_org_name(client: &Client, team: &Team) -> Option<i32> {
    let re = Regex::new(r":([^:]+):").unwrap();
    let org_name = re.captures(&team.login)?.get(1)?.as_str();

    // GET https://api.github.com/orgs/rust-lang-nursery
    let res = github_http_get(client, &format!("https://api.github.com/orgs/{}", org_name))?;
    if !res.status().is_success() {
        return None;
    }

    #[derive(Deserialize)]
    struct GithubOrganization {
        id: i32,
    }

    let org = res.json::<GithubOrganization>().ok()?;

    Some(org.id)
}

fn github_http_get(client: &Client, url: &str) -> Option<Response> {
    let gh_client_id = env::var("GH_CLIENT_ID").expect("must set GH_CLIENT_ID");
    let gh_client_secret = env::var("GH_CLIENT_SECRET").expect("must set GH_CLIENT_SECRET");

    let resp_result = client
        .get(url)
        .header(reqwest::header::ACCEPT, "application/vnd.github.v3+json")
        .header(reqwest::header::USER_AGENT, "crates.io (https://crates.io)")
        .basic_auth(&gh_client_id, Some(&gh_client_secret))
        .send();

    resp_result.ok()
}
<commit_msg>Sleep between GitHub API calls<commit_after>// Queries GitHub and backfills organization IDs for all teams without one
//
// Usage:
//      cargo run --bin backfill-org-ids

#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{db, models::Team, schema::teams};

use diesel::prelude::*;
use regex::Regex;
use reqwest::blocking::{Client, Response};
use serde::Deserialize;
use std::{env, thread, time};

fn main() {
    let conn = db::connect_now().unwrap();
    let client = Client::new();
    backfill_org_ids(&conn, &client);
}

fn backfill_org_ids(conn: &PgConnection, client: &Client) {
    let teams = teams::table
        .filter(teams::org_id.is_null())
        .load::<Team>(conn)
        .unwrap();

    let mut found = 0;
    for team in &teams {
        let option_org_id = query_for_org_id(client, team);
        match option_org_id {
            Some(org_id) => {
                found += 1;
                let update_result = diesel::update(teams::table)
                    .filter(teams::github_id.eq(team.github_id))
                    .set(teams::org_id.eq(org_id))
                    .execute(conn);
                if let Err(msg) = update_result {
                    println!(
                        "problem when updating record for team '{}': {}",
                        team.login, msg
                    );
                }
            }
            None => println!("could not find org id for team '{}'", team.login),
        }
        thread::sleep(time::Duration::from_secs(1));
    }

    println!(
        "Recorded organization ids for {} of {} teams",
        found,
        teams.len()
    );
}

fn query_for_org_id(client: &Client, team: &Team) -> Option<i32> {
    query_using_team_id(client, team).or_else(|| query_using_org_name(client, team))
}

fn query_using_team_id(client: &Client, team: &Team) -> Option<i32> {
    // GET https://api.github.com/teams/2874034
    let res = github_http_get(
        client,
        &format!("https://api.github.com/teams/{}", team.github_id),
    )?;

    // HTTP/1.1 404 Not Found
    // link: <https://docs.github.com/changes/2020-01-21-moving-the-team-api-endpoints/>; rel="deprecation"; type="text/html", <https://api.github.com/organizations/14631425/team/2874034>; rel="alternate"
    let link = res.headers().get("Link")?.to_str().ok()?;
    let links = parse_link_header::parse(link).ok()?;
    let re = Regex::new(r"/organizations/(\d+)/team").ok()?;
    let re_captures = re.captures(&links.get(&Some("alternate".into()))?.raw_uri)?;
    let org_id_str = re_captures.get(1)?.as_str();
    let org_id = i32::from_str_radix(&org_id_str, 10).ok()?;

    if org_id == 0 {
        None
    } else {
        Some(org_id)
    }
}

fn query_using_org_name(client: &Client, team: &Team) -> Option<i32> {
    let re = Regex::new(r":([^:]+):").unwrap();
    let org_name = re.captures(&team.login)?.get(1)?.as_str();

    // GET https://api.github.com/orgs/rust-lang-nursery
    let res = github_http_get(client, &format!("https://api.github.com/orgs/{}", org_name))?;
    if !res.status().is_success() {
        return None;
    }

    #[derive(Deserialize)]
    struct GithubOrganization {
        id: i32,
    }

    let org = res.json::<GithubOrganization>().ok()?;

    Some(org.id)
}

fn github_http_get(client: &Client, url: &str) -> Option<Response> {
    let gh_client_id = env::var("GH_CLIENT_ID").expect("must set GH_CLIENT_ID");
    let gh_client_secret = env::var("GH_CLIENT_SECRET").expect("must set GH_CLIENT_SECRET");

    let resp_result = client
        .get(url)
        .header(reqwest::header::ACCEPT, "application/vnd.github.v3+json")
        .header(reqwest::header::USER_AGENT, "crates.io (https://crates.io)")
        .basic_auth(&gh_client_id, Some(&gh_client_secret))
        .send();

    resp_result.ok()
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use super::{CreateAllowedMentions, CreateEmbed};
#[cfg(feature = "unstable_discord_api")]
use crate::builder::CreateComponents;
use crate::internal::prelude::*;
use crate::model::channel::MessageFlags;
use crate::utils;

/// A builder to specify the fields to edit in an existing message.
///
/// # Examples
///
/// Editing the content of a [`Message`] to `"hello"`:
///
/// ```rust,no_run
/// # use serenity::model::id::{ChannelId, MessageId};
/// # #[cfg(feature = "client")]
/// # use serenity::client::Context;
/// # #[cfg(feature = "framework")]
/// # use serenity::framework::standard::{CommandResult, macros::command};
/// #
/// # #[cfg(all(feature = "model", feature = "utils", feature = "framework"))]
/// # #[command]
/// # async fn example(ctx: &Context) -> CommandResult {
/// # let mut message = ChannelId(7).message(&ctx, MessageId(8)).await?;
/// message.edit(ctx, |m| m.content("hello")).await?;
/// # Ok(())
/// # }
/// ```
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Default)]
pub struct EditMessage(pub HashMap<&'static str, Value>);

impl EditMessage {
    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self.0.insert("content", Value::String(content.to_string()));
        self
    }

    fn _add_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);

        let embeds = self.0.entry("embeds").or_insert_with(|| Value::Array(Vec::new()));
        let embeds_array = embeds.as_array_mut().expect("Embeds must be an array");

        embeds_array.push(embed);

        self
    }

    /// Add an embed for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embed()`] to replace existing
    /// embeds.
    pub fn add_embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self._add_embed(embed)
    }

    /// Add multiple embeds for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embeds()`] to replace existing
    /// embeds.
    pub fn add_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::set_embed()`].
    ///
    /// **Note**: This will replace all existing embeds. Use
    /// [`Self::add_embed()`] to add an additional embed.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::embed()`].
    ///
    /// **Note**: This will replace all existing embeds.
    /// Use [`Self::add_embed()`] to add an additional embed.
    pub fn set_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set multiple embeds for the message.
    ///
    /// **Note**: This will replace all existing embeds. Use [`Self::add_embeds()`] to keep existing
    /// embeds.
    pub fn set_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Suppress or unsuppress embeds in the message, this includes those generated by Discord
    /// themselves.
    pub fn suppress_embeds(&mut self, suppress: bool) -> &mut Self {
        // `1 << 2` is defined by the API to be the SUPPRESS_EMBEDS flag.
        // At the time of writing, the only accepted value in "flags" is `SUPPRESS_EMBEDS` for editing messages.
        let flags = if suppress { 1 << 2 } else { 0 };
        self.0.insert("flags", serde_json::Value::Number(serde_json::Number::from(flags)));

        self
    }

    /// Set the allowed mentions for the message.
    pub fn allowed_mentions<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateAllowedMentions) -> &mut CreateAllowedMentions,
    {
        let mut allowed_mentions = CreateAllowedMentions::default();
        f(&mut allowed_mentions);
        let map = utils::hashmap_to_json_map(allowed_mentions.0);
        let allowed_mentions = Value::Object(map);

        self.0.insert("allowed_mentions", allowed_mentions);
        self
    }

    /// Sets the components of this message.
    #[cfg(feature = "unstable_discord_api")]
    pub fn components<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateComponents) -> &mut CreateComponents,
    {
        let mut components = CreateComponents::default();
        f(&mut components);

        self.0.insert("components", Value::Array(components.0));
        self
    }

    /// Sets the flags for the message.
    pub fn flags(&mut self, flags: MessageFlags) -> &mut Self {
        self.0.insert("flags", Value::Number(serde_json::Number::from(flags.bits)));
        self
    }
}
<commit_msg>Add `set_components` to `EditMessage` (#1740)<commit_after>use std::collections::HashMap;

use super::{CreateAllowedMentions, CreateEmbed};
#[cfg(feature = "unstable_discord_api")]
use crate::builder::CreateComponents;
use crate::internal::prelude::*;
use crate::model::channel::MessageFlags;
use crate::utils;

/// A builder to specify the fields to edit in an existing message.
///
/// # Examples
///
/// Editing the content of a [`Message`] to `"hello"`:
///
/// ```rust,no_run
/// # use serenity::model::id::{ChannelId, MessageId};
/// # #[cfg(feature = "client")]
/// # use serenity::client::Context;
/// # #[cfg(feature = "framework")]
/// # use serenity::framework::standard::{CommandResult, macros::command};
/// #
/// # #[cfg(all(feature = "model", feature = "utils", feature = "framework"))]
/// # #[command]
/// # async fn example(ctx: &Context) -> CommandResult {
/// # let mut message = ChannelId(7).message(&ctx, MessageId(8)).await?;
/// message.edit(ctx, |m| m.content("hello")).await?;
/// # Ok(())
/// # }
/// ```
///
/// [`Message`]: crate::model::channel::Message
#[derive(Clone, Debug, Default)]
pub struct EditMessage(pub HashMap<&'static str, Value>);

impl EditMessage {
    /// Set the content of the message.
    ///
    /// **Note**: Message contents must be under 2000 unicode code points.
    #[inline]
    pub fn content<D: ToString>(&mut self, content: D) -> &mut Self {
        self.0.insert("content", Value::String(content.to_string()));
        self
    }

    fn _add_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        let map = utils::hashmap_to_json_map(embed.0);
        let embed = Value::Object(map);

        let embeds = self.0.entry("embeds").or_insert_with(|| Value::Array(Vec::new()));
        let embeds_array = embeds.as_array_mut().expect("Embeds must be an array");

        embeds_array.push(embed);

        self
    }

    /// Add an embed for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embed()`] to replace existing
    /// embeds.
    pub fn add_embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self._add_embed(embed)
    }

    /// Add multiple embeds for the message.
    ///
    /// **Note**: This will keep all existing embeds. Use [`Self::set_embeds()`] to replace existing
    /// embeds.
    pub fn add_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::set_embed()`].
    ///
    /// **Note**: This will replace all existing embeds. Use
    /// [`Self::add_embed()`] to add an additional embed.
    pub fn embed<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateEmbed) -> &mut CreateEmbed,
    {
        let mut embed = CreateEmbed::default();
        f(&mut embed);
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set an embed for the message.
    ///
    /// Equivalent to [`Self::embed()`].
    ///
    /// **Note**: This will replace all existing embeds.
    /// Use [`Self::add_embed()`] to add an additional embed.
    pub fn set_embed(&mut self, embed: CreateEmbed) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        self._add_embed(embed)
    }

    /// Set multiple embeds for the message.
    ///
    /// **Note**: This will replace all existing embeds. Use [`Self::add_embeds()`] to keep existing
    /// embeds.
    pub fn set_embeds(&mut self, embeds: Vec<CreateEmbed>) -> &mut Self {
        self.0.insert("embeds", Value::Array(Vec::new()));
        for embed in embeds {
            self._add_embed(embed);
        }

        self
    }

    /// Suppress or unsuppress embeds in the message, this includes those generated by Discord
    /// themselves.
    pub fn suppress_embeds(&mut self, suppress: bool) -> &mut Self {
        // `1 << 2` is defined by the API to be the SUPPRESS_EMBEDS flag.
        // At the time of writing, the only accepted value in "flags" is `SUPPRESS_EMBEDS` for editing messages.
        let flags = if suppress { 1 << 2 } else { 0 };
        self.0.insert("flags", serde_json::Value::Number(serde_json::Number::from(flags)));

        self
    }

    /// Set the allowed mentions for the message.
    pub fn allowed_mentions<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateAllowedMentions) -> &mut CreateAllowedMentions,
    {
        let mut allowed_mentions = CreateAllowedMentions::default();
        f(&mut allowed_mentions);
        let map = utils::hashmap_to_json_map(allowed_mentions.0);
        let allowed_mentions = Value::Object(map);

        self.0.insert("allowed_mentions", allowed_mentions);
        self
    }

    /// Creates components for this message.
    #[cfg(feature = "unstable_discord_api")]
    pub fn components<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateComponents) -> &mut CreateComponents,
    {
        let mut components = CreateComponents::default();
        f(&mut components);

        self.0.insert("components", Value::Array(components.0));
        self
    }

    /// Sets the components of this message.
    #[cfg(feature = "unstable_discord_api")]
    pub fn set_components(&mut self, components: CreateComponents) -> &mut Self {
        self.0.insert("components", Value::Array(components.0));
        self
    }

    /// Sets the flags for the message.
    pub fn flags(&mut self, flags: MessageFlags) -> &mut Self {
        self.0.insert("flags", Value::Number(serde_json::Number::from(flags.bits)));
        self
    }
}
<|endoftext|>


<commit_before>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn (needle: str, haystack: str, nn: uint) -> [uint] {

   let results = [];

   // empty haystack
   if str::len(haystack) == 0u {
      ret results;
   }

   // empty needle
   if str::len(needle) == 0u {
      vec::push(results, 0u);
      ret results;
   }

   // needle too large
   if str::len(haystack) < str::len(needle) {
      ret results;
   }

   // generate the tables
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   // simplify the table referencing
   let getShift = fn@(pos: uint) -> uint {
      let charShift, prefShift; // also: ct, pt, needle

      assert needle != "";
      assert pos >= 0u;
      assert pos < str::len(needle);

      alt ct.find(needle[pos] as uint) {
         option::none    { charShift = str::len(needle);}
         option::some(x) { charShift = x;}
      }

      let offset = str::len(needle) - pos;

      assert offset >= 0u;
      assert offset < str::len(needle);

      alt pt.find(offset) {
         option::none { fail "something is out of range" }
         option::some(x) { prefShift = x;}
      }

      std::io::println(#fmt("<charShift: %u, prefShift: %u>", charShift, prefShift));
      ret greaterOf(charShift, prefShift);
   };

   let outerLim  = str::len(haystack);
   let windowLim = str::len(needle);

   // step up through the haystack
   let outerii = 0u;
   while outerii < outerLim - windowLim + 1u {

      // step back through needle
      let windowii = windowLim;
      while 0u < windowii
            && (outerii + (windowii - 1u)) < outerLim  // don't exceed haystack
      {
         windowii -= 1u;

         std::io::println(#fmt("%c@%u =? %c@%u",
                          needle[windowii] as char,
                          windowii,
                          haystack[outerii+windowii] as char,
                          outerii + windowii));

         // if still matching
         if needle[windowii] == haystack[outerii+windowii] {

            // if full match
            if windowii == 0u {
               std::io::println(#fmt("[pushing %u]", outerii));
               vec::push(results, outerii);

               if vec::len(results) >= nn {
                  ret results;
               } else {
                  outerii += windowLim;
               }
            }
         } else {
            outerii +=
               if windowii == windowLim - 1u {
                  // not matching yet
                  1u
               } else {
                  // partial match
                  getShift(windowLim - windowii)
               };

            break;
         }
      }
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len(needle);

   let jj = len - 1u; // drop the last byte

   assert jj >= 0u;
   assert jj < str::len(needle);

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

//#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> unsafe {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   // WAIT, HOW IS THIS ALLOWED TO MUTATE mm?
   let fill = fn@(kk: uint, vv: uint) {
      if ! mm.contains_key(kk) {
         mm.insert(kk, vv);
         std::io::println(#fmt("%u => %u", kk, vv));
      }
   };

   let lim   = str::len(needle);
   assert 0u < lim;

   // step to larger suffixes
   let sii = 0u;
   while sii < lim {

      // tail of the needle we seek
      let suffix      = str::unsafe::slice_bytes(needle, lim - sii,      lim);
      let suffix_plus = str::unsafe::slice_bytes(needle, lim - sii - 1u, lim);
      let slen = str::len(suffix);

      // step to smaller prefixes
      let pii = lim - 1u;
      while pii > 0u {

         // a prefix of the needle that might be matched by
         // a partial match of a suffix
         // (which we might want to jump to)
         let prefix = str::unsafe::slice_bytes(needle, 0u, pii);

         //let msg  = "<"+suffix+"("+#fmt("%u",sii)+")";
         //let msg2 = prefix+"("+#fmt("%u",pii)+")>";
         let msg  = "<suf("+#fmt("%u",sii)+")";
         let msg2 = "pref("+#fmt("%u",pii)+")>";
         std::io::println(msg + " × " + msg2);

         // suffix might be fully matched
         let is_suffix_matched =
            str::ends_with(prefix, suffix)
            && !str::ends_with(prefix, suffix_plus)
            &&  slen < str::len(prefix);

         // prefix is bigger than suffix, only tail can match
         let is_suffix_partially_matched =
            str::len(prefix) <= str::len(suffix)
            && str::ends_with(suffix, prefix);

         if is_suffix_matched || is_suffix_partially_matched {
            fill(sii, lim-pii);
         }

         pii -= 1u;
      }

      // no matching prefix
      fill(sii, lim-pii);

      sii += 1u;
   }

   ret mm;
}

//#[test]
fn test_prefix_table_ascii() {
   let pt = prefix_table("ANPANMAN");
                            //      ... 8

   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

//#[test]
fn test_prefix_table_utf8() {
   let pt = prefix_table("ประเ");

   assert  1u == pt.get(0u);
   assert 12u == pt.get(3u);
   assert 12u == pt.get(6u);
   assert 12u == pt.get(9u);
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];

   vec::push(vv, "");
   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, 0u, ii+1u));
   }

   ret vv;
}

//#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
   assert [""] == prefixes("");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let lim = str::len(ss);

   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, ii, lim));
   }
   vec::push(vv, "");

   ret vv;
}

//#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
   assert [""] == suffixes("");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

//#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_(needle: str, haystack: str) -> option<uint> {
   let found = findn(needle, haystack, 1u);

   alt vec::len(found) {
      0u { option::none }
      xx { option::some(found[0u]) }
   }
}

//#[test]
fn test_findn() {
   assert [] == findn("banana", "apple pie", 1u);
   assert (findn("abc", "abcxxxxxx", 1u) == [0u]);
   assert (findn("abc", "xxxabcxxx", 1u) == [3u]);
   assert (findn("abc", "xxxxxxabc", 1u) == [6u]);
   assert (findn("abc", "xxxabcabc", 1u) == [3u]);
   assert (findn("abc", "xxxabcabc", 5u) == [3u, 6u]);
   assert (findn("abc", "xxxabcxabc", 5u) == [3u, 7u]);
   assert (findn("abc", "xxxabcxxabc", 5u) == [3u, 8u]);
}

//#[test]
fn test_find_ascii() {
  assert (find_("banana", "apple pie") == option::none);
  assert (find_("", "") == option::none);
  assert (find_("abc", "abcxxxxxx") == option::some(0u));
  assert (find_("abc", "xxxabcxxx") == option::some(3u));
  assert (find_("abc", "xxxxxxabc") == option::some(6u));
}

//#[test]
fn test_find_utf8() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("", data)     == option::some( 0u));
  assert (find_("ประเ", data) == option::some( 0u));
  assert (find_("ะเ", data)   == option::some( 6u));
  assert (find_("ไท华", data) == option::none);
}

#[test]
fn test_find_B() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("中华", data) == option::some(30u));
}

<commit_msg>working fully?<commit_after>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn (needle: str, haystack: str, nn: uint) -> [uint] {

   let results = [];

   // empty haystack
   if str::len(haystack) == 0u {
      ret results;
   }

   // empty needle
   if str::len(needle) == 0u {
      vec::push(results, 0u);
      ret results;
   }

   // needle too large
   if str::len(haystack) < str::len(needle) {
      ret results;
   }

   // generate the tables
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   // simplify the table referencing
   let getShift = fn@(pos: uint) -> uint {
      let charShift, prefShift; // also: ct, pt, needle

      assert needle != "";
      assert pos >= 0u;
      assert pos < str::len(needle);

      alt ct.find(needle[pos] as uint) {
         option::none    { charShift = str::len(needle);}
         option::some(x) { charShift = x;}
      }

      let offset = str::len(needle) - pos;

      assert offset >= 0u;
      assert offset < str::len(needle);

      alt pt.find(offset) {
         option::none { fail "something is out of range" }
         option::some(x) { prefShift = x;}
      }

      std::io::println(#fmt("<charShift: %u, prefShift: %u>", charShift, prefShift));
      ret greaterOf(charShift, prefShift);
   };

   let outerLim  = str::len(haystack);
   let windowLim = str::len(needle);

   // step up through the haystack
   let outerii = 0u;
   while outerii < outerLim - windowLim + 1u {

      // step back through needle
      let windowii = windowLim;
      while 0u < windowii
            && (outerii + (windowii - 1u)) < outerLim  // don't exceed haystack
      {
         windowii -= 1u;

         //std::io::println(#fmt("%c@%u =? %c@%u",
         std::io::println(#fmt("%02x.@%u =? %02x.@%u",
                          needle[windowii] as uint,
                          windowii,
                          haystack[outerii+windowii] as uint,
                          outerii + windowii));

         // if still matching
         if needle[windowii] == haystack[outerii+windowii] {

            // if full match
            if windowii == 0u {
               std::io::println(#fmt("[pushing %u]", outerii));
               vec::push(results, outerii);

               if vec::len(results) >= nn {
                  ret results;
               } else {
                  outerii += windowLim;
               }
            }
         } else {
            outerii +=
               if windowii == windowLim - 1u {
                  // not matching yet
                  1u
               } else {
                  // partial match
                  getShift(windowLim - windowii)
               };

            break;
         }
      }
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len(needle);

   let jj = len - 1u; // drop the last byte

   assert jj >= 0u;
   assert jj < str::len(needle);

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> unsafe {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   // WAIT, HOW IS THIS ALLOWED TO MUTATE mm?
   let fill = fn@(kk: uint, vv: uint) {
      if ! mm.contains_key(kk) {
         mm.insert(kk, vv);
         std::io::println(#fmt("%u => %u", kk, vv));
      }
   };

   let lim   = str::len(needle);
   assert 0u < lim;

   // step to larger suffixes
   let sii = 0u;
   while sii < lim {

      // tail of the needle we seek
      let suffix      = str::unsafe::slice_bytes(needle, lim - sii,      lim);
      let suffix_plus = str::unsafe::slice_bytes(needle, lim - sii - 1u, lim);
      let slen = str::len(suffix);

      // step to smaller prefixes
      let pii = lim - 1u;
      while pii > 0u {

         // a prefix of the needle that might be matched by
         // a partial match of a suffix
         // (which we might want to jump to)
         let prefix = str::unsafe::slice_bytes(needle, 0u, pii);

         //let msg  = "<"+suffix+"("+#fmt("%u",sii)+")";
         //let msg2 = prefix+"("+#fmt("%u",pii)+")>";
         let msg  = "<suf("+#fmt("%u",sii)+")";
         let msg2 = "pref("+#fmt("%u",pii)+")>";
         std::io::println(msg + " × " + msg2);

         // suffix might be fully matched
         let is_suffix_matched =
            str::ends_with(prefix, suffix)
            && !str::ends_with(prefix, suffix_plus)
            &&  slen < str::len(prefix);

         // prefix is bigger than suffix, only tail can match
         let is_suffix_partially_matched =
            str::len(prefix) <= str::len(suffix)
            && str::ends_with(suffix, prefix);

         if is_suffix_matched || is_suffix_partially_matched {
            fill(sii, lim-pii);
         }

         pii -= 1u;
      }

      // no matching prefix
      fill(sii, lim-pii);

      sii += 1u;
   }

   ret mm;
}

#[test]
fn test_prefix_table_ascii() {
   let pt = prefix_table("ANPANMAN");
                            //      ... 8

   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

#[test]
fn test_prefix_table_utf8() {
   let pt = prefix_table("ประเ");

   assert  1u == pt.get(0u);
   assert 12u == pt.get(3u);
   assert 12u == pt.get(6u);
   assert 12u == pt.get(9u);
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];

   vec::push(vv, "");
   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, 0u, ii+1u));
   }

   ret vv;
}

#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
   assert [""] == prefixes("");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let lim = str::len(ss);

   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, ii, lim));
   }
   vec::push(vv, "");

   ret vv;
}

#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
   assert [""] == suffixes("");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_(needle: str, haystack: str) -> option<uint> {
   let found = findn(needle, haystack, 1u);

   alt vec::len(found) {
      0u { option::none }
      xx { option::some(found[0u]) }
   }
}

#[test]
fn test_findn() {
   assert [] == findn("banana", "apple pie", 1u);
   assert (findn("abc", "abcxxxxxx", 1u) == [0u]);
   assert (findn("abc", "xxxabcxxx", 1u) == [3u]);
   assert (findn("abc", "xxxxxxabc", 1u) == [6u]);
   assert (findn("abc", "xxxabcabc", 1u) == [3u]);
   assert (findn("abc", "xxxabcabc", 5u) == [3u, 6u]);
   assert (findn("abc", "xxxabcxabc", 5u) == [3u, 7u]);
   assert (findn("abc", "xxxabcxxabc", 5u) == [3u, 8u]);
}

#[test]
fn test_find_ascii() {
  assert (find_("banana", "apple pie") == option::none);
  assert (find_("", "") == option::none);
  assert (find_("abc", "abcxxxxxx") == option::some(0u));
  assert (find_("abc", "xxxabcxxx") == option::some(3u));
  assert (find_("abc", "xxxxxxabc") == option::some(6u));
}

#[test]
fn test_find_utf8() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("ไท华", data) == option::none);
  assert (find_("", data)     == option::some( 0u));
  assert (find_("ประเ", data) == option::some( 0u));
  assert (find_("ะเ", data)   == option::some( 6u));
  assert (find_("ระ", data) == option::some(3u));
  assert (find_("ศไทย中华", data) == option::some(15u));
  assert (find_("ไทย中华", data) == option::some(18u));
  assert (find_("ย中华", data) == option::some(24u));
  assert (find_("中华", data) == option::some(27u));
}

<|endoftext|>