<commit_before>//! The interface for interacting with TMUX sessions. All the commands that are
/// built up during the parsing phase get matched to functions here. The
/// functions in this module all build up strings the get passed to a private
/// call. The private call converts them to CStrings and makes an "unsafe" system
/// call. All functions go through this `call` function as a common gateway to
/// system calls and can all be easily logged there.

pub mod config;

use libc::system;
use std::ffi::CString;
use std::process::{Command, ExitStatus, Output};
use std::io;

/// The program to call commands on.
static TMUX_NAME: &'static str = "tmux";

/// The gateway to calling any functions on tmux. All public functions in this
/// module will be fed through this `call` function. This functions purpose is to
/// turn string based tmux function calls in to a `CString` and call out to the
/// system with it.
///
/// command: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// call("new-window -t muxed -c ~/Projects/muxed/".to_string());
/// ```
///
/// # Safety
///
/// This function will make an `unsafe` call out to the system to execute tmux
/// related commands.
fn call(command: String) -> () {
    let line = format!("{} {} {}", TMUX_NAME, command, ">/dev/null");
    let system_call = CString::new(line.clone()).unwrap();
    //println!("{}", line.clone());
    unsafe { system(system_call.as_ptr()); };
}

/// The gateway to calling any functions on tmux. Most public functions in this
/// module will be fed through this `call` function. This safely creates a new
/// thread to execute the command on. We say "Most" public functions will use
/// this as `attach` specificaly does not use it.
///
/// args: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// call(&["new-window", "-t", "muxed", "-c", "~/Projects/muxed/"]);
/// ```
fn call1(args: &[&str]) -> Result<Output, io::Error> {
    //println!("{}", line.clone());
    Command::new(TMUX_NAME).args(args).output()
}

/// Attach is called as the last function in a set of commands. After the tmux
/// env has been setup by all previous commands this attaches the user to their
/// daemonized tmux session.
///
/// # Examples
///
/// ```
/// let session_name = "muxed".to_string();
/// tmux::attach(muxed);
/// ```
/// session_name: The active tmux session name.
pub fn attach(session_name: &String) -> () {
    call(format!("attach -t {}", session_name));
}

/// New session is the first call made in any sequence of commands. It initiates
/// a new tmux session with a default first window name.
/// *Why a randomized first window name?*
///   This is because the `new-session` tmux command does not support the `-c`
/// flag as `new-window` and `split-window` do. So if the first window requires
/// being changed to a default directory `send-keys` must be used after the
/// session and first window are opened. This means the first window is treated in
/// a different code path than any other window that is opened.
/// Instead I've opted to open the session with a randomized (no conflicts)
/// named window, and we close this window out before attaching the user. This
/// allows for us to treat all user defined windows the same.
///
/// session_name: The name of the session being created.
/// tmp_name: The named first window that we will close out.
///
/// # Examples
///
/// ```
/// use rand::random;
///
/// let session_name = "muxed".to_string();
/// let tmp_window_name = random::<u16>().to_string();
/// tmux::new_session(session_name, tmp_window_name);
/// ```
///
/// session_name: The active tmux session name.
/// tmp_name: The name for the temp initial window that is created with a new
/// session.
pub fn new_session(session_name: &String, window_name: &String) -> () {
    call(format!("new -d -s {} -n {}", session_name, window_name));
}

/// Split window acts as the command to target named windows in a session to
/// send a make separate a single pane into two panes. Split window should target
/// a specific pane even if only a single pane exists.
///
/// # Examples
///
/// ```
/// let target = "muxed:cargo.0".to_string();
/// tmux::split_window(target, None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn split_window(target: &String) -> () {
    call(format!("split-window -t {}", target));
}

/// New window opens a new window in the named session with the provided window
/// name.
///
/// # Examples
///
/// ```
/// tmux::new_window("muxed".to_string(), "vim".to_string(), None);
/// ```
///
/// session_name: The active tmux session name.
/// window_name: The desired window name for the new window.
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn new_window(session_name: &String, window_name: &String) -> () {
    call(format!("new-window -t {} -n {}", session_name, window_name));
}

/// The layout function will adjust the layout of a tmux window that already has
/// multiple panes. Currently it will only accept standard tmux layout types.
///
/// Possible layout options: even-horizontal, even-vertical, main-horizontal,
/// main-vertical, or tiled.
///
/// # Examples
///
/// ```
/// tmux::layout("muxed:cargo.0".to_string(), "main-vertical".to_string(), None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// layout: The predefined tmux named layout.
pub fn layout(target: &String, layout: &String) -> () {
    call(format!("select-layout -t {} {}", target, layout));
}

/// Send Keys executes literal key commands in specified target windows. This is
/// the execution method to perform actions like tailing logs, starting servers,
/// or opening editors.
///
/// `KPEnter` represent the keyboard press of the "Enter" key. So the execution
/// is a user input command followed by "enter"
///
/// # Examples
///
/// ```
/// tmux::send_keys("muxed:cargo.0".to_string(), "vim .".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// exec: The system command to be executed in a particular pane.
pub fn send_keys(target: &String, exec: &String) -> () {
    call(format!("send-keys -t {} '{}' KPEnter", target, exec));
}

/// This is used to re-select the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_window("muxed:cargo.0".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_window(target: &String) -> () {
    call(format!("select-window -t {}", target));
}

/// This is used to re-select the top pane in the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_pane("muxed:cargo.top".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_pane(target: &String) -> () {
    call(format!("select-pane -t {}", target));
}

/// List Windows is used firgure out if a named session is already running.
///
/// # Examples
///
/// ```
/// tmux::has_session("muxed".to_string());
/// => ExitStatus
/// ```
///
/// target: A string represented by the {named_session}
pub fn has_session(target: &String) -> ExitStatus {
    let output = Command::new(TMUX_NAME)
                     .arg("has-session")
                     .arg("-t")
                     .arg(target)
                     .output()
                     .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    output.status
}

/// Read the tmux config and return a config object
///
/// # Examples
///
/// ```
/// tmux::get_config();
/// => "some-option false\npane-base-index 0"
/// ```
pub fn get_config() -> String {
    let output = Command::new(TMUX_NAME)
                     .args(&["start-server", ";", "show-options", "-g"])
                     .output()
                     .unwrap_or_else(|e| { panic!("couldn't get tmux options: {}", e) });

    String::from_utf8_lossy(&output.stdout).to_string()
}
<commit_msg>refactor(tmux/mod.rs): Move to call1 for all calls<commit_after>//! The interface for interacting with TMUX sessions. All the commands that are
/// built up during the parsing phase get matched to functions here. The
/// functions in this module all build up strings the get passed to a private
/// call. The private call converts them to CStrings and makes an "unsafe" system
/// call. All functions go through this `call` function as a common gateway to
/// system calls and can all be easily logged there.

pub mod config;

use libc::system;
use std::ffi::CString;
use std::process::{Command, ExitStatus, Output};
use std::io;

/// The program to call commands on.
static TMUX_NAME: &'static str = "tmux";

/// The gateway to calling any functions on tmux. All public functions in this
/// module will be fed through this `call` function. This functions purpose is to
/// turn string based tmux function calls in to a `CString` and call out to the
/// system with it.
///
/// command: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// call("new-window -t muxed -c ~/Projects/muxed/".to_string());
/// ```
///
/// # Safety
///
/// This function will make an `unsafe` call out to the system to execute tmux
/// related commands.
fn call(command: String) -> () {
    let line = format!("{} {} {}", TMUX_NAME, command, ">/dev/null");
    let system_call = CString::new(line.clone()).unwrap();
    //println!("{}", line.clone());
    unsafe { system(system_call.as_ptr()); };
}

/// The gateway to calling any functions on tmux. Most public functions in this
/// module will be fed through this `call` function. This safely creates a new
/// thread to execute the command on. We say "Most" public functions will use
/// this as `attach` specificaly does not use it.
///
/// args: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// call(&["new-window", "-t", "muxed", "-c", "~/Projects/muxed/"]);
/// ```
fn call1(args: &[&str]) -> Result<Output, io::Error> {
    //println!("{}", line.clone());
    Command::new(TMUX_NAME).args(args).output()
}

/// Attach is called as the last function in a set of commands. After the tmux
/// env has been setup by all previous commands this attaches the user to their
/// daemonized tmux session.
///
/// # Examples
///
/// ```
/// let session_name = "muxed".to_string();
/// tmux::attach(muxed);
/// ```
/// session_name: The active tmux session name.
pub fn attach(session_name: &String) -> () {
    call(format!("attach -t {}", session_name));
}

/// New session is the first call made in any sequence of commands. It initiates
/// a new tmux session with a default first window name.
/// *Why a randomized first window name?*
///   This is because the `new-session` tmux command does not support the `-c`
/// flag as `new-window` and `split-window` do. So if the first window requires
/// being changed to a default directory `send-keys` must be used after the
/// session and first window are opened. This means the first window is treated in
/// a different code path than any other window that is opened.
/// Instead I've opted to open the session with a randomized (no conflicts)
/// named window, and we close this window out before attaching the user. This
/// allows for us to treat all user defined windows the same.
///
/// session_name: The name of the session being created.
/// tmp_name: The named first window that we will close out.
///
/// # Examples
///
/// ```
/// use rand::random;
///
/// let session_name = "muxed".to_string();
/// let tmp_window_name = random::<u16>().to_string();
/// tmux::new_session(session_name, tmp_window_name);
/// ```
///
/// session_name: The active tmux session name.
/// tmp_name: The name for the temp initial window that is created with a new
/// session.
pub fn new_session(session_name: &String, window_name: &String) -> () {
    //call(format!("new -d -s {} -n {}", session_name, window_name));
    call1(&["new", "-d", "-s", session_name, "-n", window_name]);
}

/// Split window acts as the command to target named windows in a session to
/// send a make separate a single pane into two panes. Split window should target
/// a specific pane even if only a single pane exists.
///
/// # Examples
///
/// ```
/// let target = "muxed:cargo.0".to_string();
/// tmux::split_window(target, None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn split_window(target: &String) -> () {
    //call(format!("split-window -t {}", target));
    call1(&["split-window", "-t", target]);
}

/// New window opens a new window in the named session with the provided window
/// name.
///
/// # Examples
///
/// ```
/// tmux::new_window("muxed".to_string(), "vim".to_string(), None);
/// ```
///
/// session_name: The active tmux session name.
/// window_name: The desired window name for the new window.
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn new_window(session_name: &String, window_name: &String) -> () {
    //call(format!("new-window -t {} -n {}", session_name, window_name));
    call1(&["new-window", "-t", session_name, "-n", window_name]);
}

/// The layout function will adjust the layout of a tmux window that already has
/// multiple panes. Currently it will only accept standard tmux layout types.
///
/// Possible layout options: even-horizontal, even-vertical, main-horizontal,
/// main-vertical, or tiled.
///
/// # Examples
///
/// ```
/// tmux::layout("muxed:cargo.0".to_string(), "main-vertical".to_string(), None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// layout: The predefined tmux named layout.
pub fn layout(target: &String, layout: &String) -> () {
    //call(format!("select-layout -t {} {}", target, layout));
    call1(&["select-layout", "-t", target, layout]);
}

/// Send Keys executes literal key commands in specified target windows. This is
/// the execution method to perform actions like tailing logs, starting servers,
/// or opening editors.
///
/// `KPEnter` represent the keyboard press of the "Enter" key. So the execution
/// is a user input command followed by "enter"
///
/// # Examples
///
/// ```
/// tmux::send_keys("muxed:cargo.0".to_string(), "vim .".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// exec: The system command to be executed in a particular pane.
pub fn send_keys(target: &String, exec: &String) -> () {
    //call(format!("send-keys -t {} '{}' KPEnter", target, exec));
    call1(&["send-keys", "-t", target, exec, "KPEnter"]);
}

/// This is used to re-select the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_window("muxed:cargo.0".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_window(target: &String) -> () {
    //call(format!("select-window -t {}", target));
    call1(&["select-window", "-t", target]);
}

/// This is used to re-select the top pane in the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_pane("muxed:cargo.top".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_pane(target: &String) -> () {
    //call(format!("select-pane -t {}", target));
    call1(&["select-pane", "-t", target]);
}

/// List Windows is used firgure out if a named session is already running.
///
/// # Examples
///
/// ```
/// tmux::has_session("muxed".to_string());
/// => ExitStatus
/// ```
///
/// target: A string represented by the {named_session}
pub fn has_session(target: &String) -> ExitStatus {
    let output = Command::new(TMUX_NAME)
                     .arg("has-session")
                     .arg("-t")
                     .arg(target)
                     .output()
                     .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    output.status
}

/// Read the tmux config and return a config object
///
/// # Examples
///
/// ```
/// tmux::get_config();
/// => "some-option false\npane-base-index 0"
/// ```
pub fn get_config() -> String {
    let output = Command::new(TMUX_NAME)
                     .args(&["start-server", ";", "show-options", "-g"])
                     .output()
                     .unwrap_or_else(|e| { panic!("couldn't get tmux options: {}", e) });

    String::from_utf8_lossy(&output.stdout).to_string()
}
<|endoftext|>


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

use crate::{aws::Aws, cluster::Cluster};
use failure::prelude::format_err;
use retry::{delay::Fixed, retry};
use rusoto_core::RusotoError;
use rusoto_ecr::{
    BatchGetImageRequest, DescribeImagesRequest, DescribeImagesResponse, Ecr, Image,
    ImageIdentifier, PutImageError, PutImageRequest,
};
use rusoto_ecs::{Ecs, UpdateServiceRequest};
use slog_scope::{info, warn};
use std::{thread, time::Duration};

#[derive(Clone)]
pub struct DeploymentManager {
    aws: Aws,
    cluster: Cluster,
}

const VALIDATOR_IMAGE_REPO: &str = "libra_e2e";
const CLIENT_IMAGE_REPO: &str = "libra_client";
const FAUCET_IMAGE_REPO: &str = "libra_faucet";
pub const SOURCE_TAG: &str = "nightly";
pub const RUNNING_TAG: &str = "cluster_test";
pub const TESTED_TAG: &str = "nightly_tested";
const UPSTREAM_PREFIX: &str = "upstream_";

impl DeploymentManager {
    pub fn new(aws: Aws, cluster: Cluster) -> Self {
        Self { aws, cluster }
    }

    pub fn latest_hash_changed(&self) -> Option<String> {
        let hash = self.image_digest_by_tag(SOURCE_TAG);
        let last_tested = self.image_digest_by_tag(TESTED_TAG);
        if hash == last_tested {
            info!("Last deployed digest matches latest digest we expect, not doing redeploy");
            return None;
        }
        Some(hash)
    }

    pub fn redeploy(&mut self, hash: String) -> failure::Result<()> {
        info!("Will deploy with digest {}", hash);
        self.tag_image(
            VALIDATOR_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: Some(hash),
                image_tag: None,
            },
            RUNNING_TAG,
        )?;
        self.update_all_services()?;
        Ok(())
    }

    pub fn update_all_services(&self) -> failure::Result<()> {
        for instance in self.cluster.instances() {
            let mut request = UpdateServiceRequest::default();
            request.cluster = Some(self.aws.workplace().clone());
            request.force_new_deployment = Some(true);
            request.service = format!(
                "{w}/{w}-validator-{hash}",
                w = self.aws.workplace(),
                hash = instance.short_hash()
            );

            self.aws
                .ecs()
                .update_service(request)
                .sync()
                .map_err(|e| format_err!("Failed to update {}: {:?}", instance, e))?;
            thread::sleep(Duration::from_millis(100));
        }
        Ok(())
    }

    fn image_digest_by_tag(&self, tag: &str) -> String {
        let result = self.describe_images(tag);
        let images = result
            .image_details
            .expect("No image_details in ECR response");
        if images.len() != 1 {
            panic!("Ecr returned {} images for libra_e2e:nightly", images.len());
        }
        let image = images.into_iter().next().unwrap();
        image.image_digest.expect("No image_digest")
    }

    fn describe_images(&self, tag: &str) -> DescribeImagesResponse {
        let mut retry = 0usize;
        loop {
            let mut request = DescribeImagesRequest::default();
            request.repository_name = VALIDATOR_IMAGE_REPO.into();
            let image_id = ImageIdentifier {
                image_digest: None,
                image_tag: Some(tag.to_string()),
            };
            request.image_ids = Some(vec![image_id]);
            match self.aws.ecr().describe_images(request).sync() {
                Ok(r) => return r,
                Err(e) => {
                    if retry > 10 {
                        panic!("Failed describe_images after 10 attempts");
                    } else {
                        warn!("Transient failure in describe_images: {}", e);
                        thread::sleep(Duration::from_secs(10));
                        retry += 1;
                    }
                }
            }
        }
    }

    pub fn get_tested_upstream_commit(&self) -> failure::Result<String> {
        let digest = self.image_digest_by_tag(TESTED_TAG);
        let prev_upstream_tag = self.get_upstream_tag(&digest)?;
        Ok(prev_upstream_tag[UPSTREAM_PREFIX.len()..].to_string())
    }

    pub fn tag_tested_image(&mut self, hash: String) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(hash.clone()),
            image_tag: None,
        };
        self.tag_image(VALIDATOR_IMAGE_REPO, &image_id, TESTED_TAG)?;
        let upstream_tag = self.get_upstream_tag(&hash)?;
        self.tag_image(
            CLIENT_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;
        self.tag_image(
            FAUCET_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;

        let upstream_commit = upstream_tag[UPSTREAM_PREFIX.len()..].to_string();
        Ok(upstream_commit)
    }

    pub fn get_upstream_tag(&self, digest: &str) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(digest.to_string()),
            image_tag: None,
        };
        let images = self.get_images(VALIDATOR_IMAGE_REPO, &image_id)?;
        for image in images {
            let image_id = match image.image_id {
                Some(image_id) => image_id,
                None => continue,
            };
            let tag = match image_id.image_tag {
                Some(tag) => tag,
                None => continue,
            };
            if tag.starts_with(UPSTREAM_PREFIX) {
                return Ok(tag);
            }
        }
        Err(format_err!("Failed to find upstream tag"))
    }

    fn get_images(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
    ) -> failure::Result<Vec<Image>> {
        let mut get_request = BatchGetImageRequest::default();
        get_request.repository_name = repository.to_string();
        get_request.image_ids = vec![image_id.clone()];
        // Retry upto 10 times, waiting 10 sec between retries
        let response = retry(Fixed::from_millis(10_000).take(10), || {
            self.aws
                .ecr()
                .batch_get_image(get_request.clone())
                .sync()
                .map_err(|e| {
                    warn!(
                        "Failed to get image from repository: {:?}. Retrying...",
                        get_request.repository_name
                    );
                    e
                })
        })
        .map_err(|e| {
            format_err!(
                "Failed to get image from repository: {:?} after 10 tries: {:?}",
                get_request.repository_name,
                e
            )
        })?;
        response
            .images
            .ok_or_else(|| format_err!("No images in batch_get_image response"))
    }

    fn tag_image(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
        new_tag: &str,
    ) -> failure::Result<()> {
        let images = self.get_images(repository, &image_id)?;
        let image = images
            .into_iter()
            .next()
            .ok_or_else(|| format_err!("get_images returned 0 images"))?;
        let manifest = image
            .image_manifest
            .ok_or_else(|| format_err!("no manifest in batch_get_image response"))?;
        let mut put_request = PutImageRequest::default();
        put_request.image_manifest = manifest;
        put_request.repository_name = repository.to_string();
        put_request.image_tag = Some(new_tag.to_string());
        let result = self.aws.ecr().put_image(put_request).sync();
        if let Err(e) = result {
            if let RusotoError::Service(PutImageError::ImageAlreadyExists(_)) = e {
                info!("Tag for Image already exists {}:{}", repository, new_tag);
                Ok(())
            } else {
                Err(format_err!("Failed to tag image: {:?}", e))
            }
        } else {
            Ok(())
        }
    }
}
<commit_msg>[cluster-test] Allow to use --deploy on custom workplace<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{aws::Aws, cluster::Cluster};
use failure::prelude::format_err;
use retry::{delay::Fixed, retry};
use rusoto_core::RusotoError;
use rusoto_ecr::{
    BatchGetImageRequest, DescribeImagesRequest, DescribeImagesResponse, Ecr, Image,
    ImageIdentifier, PutImageError, PutImageRequest,
};
use rusoto_ecs::{Ecs, UpdateServiceRequest};
use slog_scope::{info, warn};
use std::{env, thread, time::Duration};

#[derive(Clone)]
pub struct DeploymentManager {
    aws: Aws,
    cluster: Cluster,
    running_tag: String,
}

const VALIDATOR_IMAGE_REPO: &str = "libra_e2e";
const CLIENT_IMAGE_REPO: &str = "libra_client";
const FAUCET_IMAGE_REPO: &str = "libra_faucet";
pub const SOURCE_TAG: &str = "nightly";
pub const TESTED_TAG: &str = "nightly_tested";
const UPSTREAM_PREFIX: &str = "upstream_";
const MASTER_PREFIX: &str = "master_";

impl DeploymentManager {
    pub fn new(aws: Aws, cluster: Cluster) -> Self {
        let running_tag = env::var("TAG").unwrap_or_else(|_| aws.workplace().to_string());
        if running_tag == SOURCE_TAG
            || running_tag == TESTED_TAG
            || running_tag.starts_with(UPSTREAM_PREFIX)
            || running_tag.starts_with(MASTER_PREFIX)
        {
            panic!(
                "Cluster test can not deploy if workplace is configured to use {} tag.\
                 Use custom tag for your workplace to use --deploy",
                running_tag
            );
        }
        info!("Will use {} tag for deployment", running_tag);
        Self {
            aws,
            cluster,
            running_tag,
        }
    }

    pub fn latest_hash_changed(&self) -> Option<String> {
        let hash = self.image_digest_by_tag(SOURCE_TAG);
        let last_tested = self.image_digest_by_tag(TESTED_TAG);
        if hash == last_tested {
            info!("Last deployed digest matches latest digest we expect, not doing redeploy");
            return None;
        }
        Some(hash)
    }

    pub fn redeploy(&mut self, hash: String) -> failure::Result<()> {
        info!("Will deploy with digest {}", hash);
        self.tag_image(
            VALIDATOR_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: Some(hash),
                image_tag: None,
            },
            &self.running_tag,
        )?;
        self.update_all_services()?;
        Ok(())
    }

    pub fn update_all_services(&self) -> failure::Result<()> {
        for instance in self.cluster.instances() {
            let mut request = UpdateServiceRequest::default();
            request.cluster = Some(self.aws.workplace().clone());
            request.force_new_deployment = Some(true);
            request.service = format!(
                "{w}/{w}-validator-{hash}",
                w = self.aws.workplace(),
                hash = instance.short_hash()
            );

            self.aws
                .ecs()
                .update_service(request)
                .sync()
                .map_err(|e| format_err!("Failed to update {}: {:?}", instance, e))?;
            thread::sleep(Duration::from_millis(100));
        }
        Ok(())
    }

    fn image_digest_by_tag(&self, tag: &str) -> String {
        let result = self.describe_images(tag);
        let images = result
            .image_details
            .expect("No image_details in ECR response");
        if images.len() != 1 {
            panic!("Ecr returned {} images for libra_e2e:nightly", images.len());
        }
        let image = images.into_iter().next().unwrap();
        image.image_digest.expect("No image_digest")
    }

    fn describe_images(&self, tag: &str) -> DescribeImagesResponse {
        let mut retry = 0usize;
        loop {
            let mut request = DescribeImagesRequest::default();
            request.repository_name = VALIDATOR_IMAGE_REPO.into();
            let image_id = ImageIdentifier {
                image_digest: None,
                image_tag: Some(tag.to_string()),
            };
            request.image_ids = Some(vec![image_id]);
            match self.aws.ecr().describe_images(request).sync() {
                Ok(r) => return r,
                Err(e) => {
                    if retry > 10 {
                        panic!("Failed describe_images after 10 attempts");
                    } else {
                        warn!("Transient failure in describe_images: {}", e);
                        thread::sleep(Duration::from_secs(10));
                        retry += 1;
                    }
                }
            }
        }
    }

    pub fn get_tested_upstream_commit(&self) -> failure::Result<String> {
        let digest = self.image_digest_by_tag(TESTED_TAG);
        let prev_upstream_tag = self.get_upstream_tag(&digest)?;
        Ok(prev_upstream_tag[UPSTREAM_PREFIX.len()..].to_string())
    }

    pub fn tag_tested_image(&mut self, hash: String) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(hash.clone()),
            image_tag: None,
        };
        self.tag_image(VALIDATOR_IMAGE_REPO, &image_id, TESTED_TAG)?;
        let upstream_tag = self.get_upstream_tag(&hash)?;
        self.tag_image(
            CLIENT_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;
        self.tag_image(
            FAUCET_IMAGE_REPO,
            &ImageIdentifier {
                image_digest: None,
                image_tag: Some(upstream_tag.clone()),
            },
            TESTED_TAG,
        )?;

        let upstream_commit = upstream_tag[UPSTREAM_PREFIX.len()..].to_string();
        Ok(upstream_commit)
    }

    pub fn get_upstream_tag(&self, digest: &str) -> failure::Result<String> {
        let image_id = ImageIdentifier {
            image_digest: Some(digest.to_string()),
            image_tag: None,
        };
        let images = self.get_images(VALIDATOR_IMAGE_REPO, &image_id)?;
        for image in images {
            let image_id = match image.image_id {
                Some(image_id) => image_id,
                None => continue,
            };
            let tag = match image_id.image_tag {
                Some(tag) => tag,
                None => continue,
            };
            if tag.starts_with(UPSTREAM_PREFIX) {
                return Ok(tag);
            }
        }
        Err(format_err!("Failed to find upstream tag"))
    }

    fn get_images(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
    ) -> failure::Result<Vec<Image>> {
        let mut get_request = BatchGetImageRequest::default();
        get_request.repository_name = repository.to_string();
        get_request.image_ids = vec![image_id.clone()];
        // Retry upto 10 times, waiting 10 sec between retries
        let response = retry(Fixed::from_millis(10_000).take(10), || {
            self.aws
                .ecr()
                .batch_get_image(get_request.clone())
                .sync()
                .map_err(|e| {
                    warn!(
                        "Failed to get image from repository: {:?}. Retrying...",
                        get_request.repository_name
                    );
                    e
                })
        })
        .map_err(|e| {
            format_err!(
                "Failed to get image from repository: {:?} after 10 tries: {:?}",
                get_request.repository_name,
                e
            )
        })?;
        response
            .images
            .ok_or_else(|| format_err!("No images in batch_get_image response"))
    }

    fn tag_image(
        &self,
        repository: &str,
        image_id: &ImageIdentifier,
        new_tag: &str,
    ) -> failure::Result<()> {
        let images = self.get_images(repository, &image_id)?;
        let image = images
            .into_iter()
            .next()
            .ok_or_else(|| format_err!("get_images returned 0 images"))?;
        let manifest = image
            .image_manifest
            .ok_or_else(|| format_err!("no manifest in batch_get_image response"))?;
        let mut put_request = PutImageRequest::default();
        put_request.image_manifest = manifest;
        put_request.repository_name = repository.to_string();
        put_request.image_tag = Some(new_tag.to_string());
        let result = self.aws.ecr().put_image(put_request).sync();
        if let Err(e) = result {
            if let RusotoError::Service(PutImageError::ImageAlreadyExists(_)) = e {
                info!("Tag for Image already exists {}:{}", repository, new_tag);
                Ok(())
            } else {
                Err(format_err!("Failed to tag image: {:?}", e))
            }
        } else {
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>use toml::decode_str;

use std::convert::From;
use std::io::Read;
use std::fs::File;

use errors::loading::Error;
use structs::{Secret, State};
use structs::states::Start;

/// State which loads configurations
#[derive(Debug)]
pub struct Load {

  /// Loaded configurations
  pub secret: Result<Secret, Error>,

}

impl Load {

  /// Load and decode the secret toml from the provided path
  pub fn load_secret(secret_path: String) -> Result<Secret, Error> {

    let mut secret_file = try!(File::open(secret_path));
    let mut secret_text = String::new();

    try!(secret_file.read_to_string(&mut secret_text));

    match decode_str::<Secret>(secret_text.as_str()) {
      Some(decoded) => Ok(decoded),
      None => Err(Error::InvalidSecretText(secret_text)),
    }

  }

}

impl From<State<Start>> for State<Load> {

  fn from(start: State<Start>) -> State<Load> {

    let secret = Load::load_secret(start.state.secret_path);

    State { state: Load { secret: secret } }

  }

}

<commit_msg>Issue #1: Remove unnecessary type<commit_after>use toml::decode_str;

use std::convert::From;
use std::io::Read;
use std::fs::File;

use errors::loading::Error;
use structs::{Secret, State};
use structs::states::Start;

/// State which loads configurations
#[derive(Debug)]
pub struct Load {

  /// Loaded configurations
  pub secret: Result<Secret, Error>,

}

impl Load {

  /// Load and decode the secret toml from the provided path
  pub fn load_secret(secret_path: String) -> Result<Secret, Error> {

    let mut secret_file = try!(File::open(secret_path));
    let mut secret_text = String::new();

    try!(secret_file.read_to_string(&mut secret_text));

    match decode_str(secret_text.as_str()) {
      Some(decoded) => Ok(decoded),
      None => Err(Error::InvalidSecretText(secret_text)),
    }

  }

}

impl From<State<Start>> for State<Load> {

  fn from(start: State<Start>) -> State<Load> {

    let secret = Load::load_secret(start.state.secret_path);

    State { state: Load { secret: secret } }

  }

}

<|endoftext|>


<commit_before>#[cfg(target_os = "linux")]
mod linux;

#[cfg(target_os = "linux")]
use self::linux::*;

#[cfg(target_os = "macos")]
mod macos;

#[cfg(target_os = "macos")]
use self::macos::*;

use std::io;
use std::ffi::{OsStr, OsString};
use std::os::unix::io::RawFd;
use std::os::unix::ffi::{OsStrExt};
use std::path::Path;

use ::libc::{c_void, size_t, c_char};

use ::util::{path_to_c, name_to_c, allocate_loop};

pub struct XAttrs {
    data: Box<[u8]>,
    offset: usize,
}

// Yes, I could avoid these allocations on linux/macos. However, if we ever want to be freebsd
// compatable, we need to be able to prepend the namespace to the extended attribute names.
// Furthermore, borrowing makes the API messy.
impl Iterator for XAttrs {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        let data = &self.data[self.offset..];
        if data.is_empty() {
            None
        } else {
            let end = data.iter().position(|&b| b == 0u8).unwrap(); // always null terminated (unless empty).
            self.offset = end + 1;
            Some(OsStr::from_bytes(&data[..end]).to_owned())
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.data.len() == self.offset {
            (0, Some(0))
        } else {
            (1, None)
        }
    }
}

pub fn get_fd(fd: RawFd, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    unsafe {
        allocate_loop(|buf, len| fgetxattr(fd, name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_fd(fd: RawFd, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe {
        fsetxattr(
            fd,
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_fd(fd: RawFd, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe { fremovexattr(fd, name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_fd(fd: RawFd) -> io::Result<XAttrs> {
    let vec = unsafe {
        try!(allocate_loop(|buf, len| flistxattr(fd, buf as *mut c_char, len as size_t)))
    };
    println!("{:?}", vec);
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

pub fn get_path(path: &Path, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    unsafe {
        allocate_loop(|buf, len| lgetxattr(path.as_ptr(), name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_path(path: &Path, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe {
        lsetxattr(
            path.as_ptr(),
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_path(path: &Path, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe { lremovexattr(path.as_ptr(), name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_path(path: &Path) -> io::Result<XAttrs> {
    let path = try!(path_to_c(path));
    let vec = unsafe {
        try!(allocate_loop(|buf, len| llistxattr(path.as_ptr(), buf as *mut c_char, len as size_t)))
    };
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

<commit_msg>Iterator can be cloned.<commit_after>#[cfg(target_os = "linux")]
mod linux;

#[cfg(target_os = "linux")]
use self::linux::*;

#[cfg(target_os = "macos")]
mod macos;

#[cfg(target_os = "macos")]
use self::macos::*;

use std::io;
use std::ffi::{OsStr, OsString};
use std::os::unix::io::RawFd;
use std::os::unix::ffi::{OsStrExt};
use std::path::Path;

use ::libc::{c_void, size_t, c_char};

use ::util::{path_to_c, name_to_c, allocate_loop};

#[derive(Clone)]
pub struct XAttrs {
    data: Box<[u8]>,
    offset: usize,
}

// Yes, I could avoid these allocations on linux/macos. However, if we ever want to be freebsd
// compatable, we need to be able to prepend the namespace to the extended attribute names.
// Furthermore, borrowing makes the API messy.
impl Iterator for XAttrs {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        let data = &self.data[self.offset..];
        if data.is_empty() {
            None
        } else {
            let end = data.iter().position(|&b| b == 0u8).unwrap(); // always null terminated (unless empty).
            self.offset = end + 1;
            Some(OsStr::from_bytes(&data[..end]).to_owned())
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.data.len() == self.offset {
            (0, Some(0))
        } else {
            (1, None)
        }
    }
}

pub fn get_fd(fd: RawFd, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    unsafe {
        allocate_loop(|buf, len| fgetxattr(fd, name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_fd(fd: RawFd, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe {
        fsetxattr(
            fd,
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_fd(fd: RawFd, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe { fremovexattr(fd, name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_fd(fd: RawFd) -> io::Result<XAttrs> {
    let vec = unsafe {
        try!(allocate_loop(|buf, len| flistxattr(fd, buf as *mut c_char, len as size_t)))
    };
    println!("{:?}", vec);
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

pub fn get_path(path: &Path, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    unsafe {
        allocate_loop(|buf, len| lgetxattr(path.as_ptr(), name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_path(path: &Path, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe {
        lsetxattr(
            path.as_ptr(),
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_path(path: &Path, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe { lremovexattr(path.as_ptr(), name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_path(path: &Path) -> io::Result<XAttrs> {
    let path = try!(path_to_c(path));
    let vec = unsafe {
        try!(allocate_loop(|buf, len| llistxattr(path.as_ptr(), buf as *mut c_char, len as size_t)))
    };
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    collections::BTreeMap,
    rc::Rc,
};

use dces::prelude::{Entity, EntityComponentManager, System};

use crate::{
    application::{Global, Tree},
    backend::Backend,
    properties::{Constraint, Enabled, Focused, Margin, Padding, Pressed, Selected},
    theme::{Selector, Theme},
    widget::{
        add_selector_to_widget, remove_selector_from_widget, Context, State, WidgetContainer,
    },
};

/// This system is used to initializes the widgets.
pub struct InitSystem {
    pub backend: Rc<RefCell<dyn Backend>>,
}

impl InitSystem {
    // init css ids.
    fn init_id(&self, node: Entity, ecm: &mut EntityComponentManager) {
        // Add css id to global id map.
        let id = if let Ok(selector) = ecm.borrow_component::<Selector>(node) {
            if let Some(id) = &selector.id {
                Some((node, id.clone()))
            } else {
                None
            }
        } else {
            None
        };

        if let Some((entity, id)) = id {
            if let Ok(global) = ecm.borrow_mut_component::<Global>(0) {
                global.id_map.insert(id, entity);
            }
        }
    }

    // Read all initial data from css
    fn read_init_from_theme(&self, node: Entity, ecm: &mut EntityComponentManager, theme: &Theme) {
        let mut margin = Margin::default();
        let mut padding = Padding::default();
        let mut constraint = Constraint::default();

        // todo: update widget by selector method!!!

        if let Ok(selector) = ecm.borrow_component::<Selector>(node) {
            let pad = theme.uint("padding", selector) as i32;

            if pad > 0 {
                padding.left = pad;
                padding.top = pad;
                padding.right = pad;
                padding.bottom = pad;
            } else {
                padding.left = theme.uint("padding-left", selector) as i32;
                padding.top = theme.uint("padding-top", selector) as i32;
                padding.right = theme.uint("padding-right", selector) as i32;
                padding.bottom = theme.uint("padding-bottom", selector) as i32;
            }

            let mar = theme.uint("margin", selector) as i32;

            if mar > 0 {
                margin.left = mar;
                margin.top = mar;
                margin.right = mar;
                margin.bottom = mar;
            } else {
                margin.left = theme.uint("margin-left", selector) as i32;
                margin.top = theme.uint("margin-top", selector) as i32;
                margin.right = theme.uint("margin-right", selector) as i32;
                margin.bottom = theme.uint("margin-bottom", selector) as i32;
            }

            constraint.min_width = theme.uint("min-width", selector) as u32;
            constraint.max_width = theme.uint("max_width-width", selector) as u32;
            constraint.min_height = theme.uint("min_height-width", selector) as u32;
            constraint.max_height = theme.uint("min-max_height", selector) as u32;
            constraint.width = theme.uint("width", selector) as u32;
            constraint.height = theme.uint("height", selector) as u32;
        }

        ecm.register_component(node, padding);
        ecm.register_component(node, margin);
        ecm.register_component(node, constraint);
    }
}

impl System<Tree> for InitSystem {
    fn run(&self, tree: &Tree, ecm: &mut EntityComponentManager) {
        let mut backend = self.backend.borrow_mut();
        let context = backend.state_context();

        // init css ids
        for node in tree.into_iter() {
            self.init_id(node, ecm);
            self.read_init_from_theme(node, ecm, context.theme);
        }
    }
}
<commit_msg>[cleanup] init system<commit_after>use std::{
    cell::RefCell,
    rc::Rc,
};

use dces::prelude::{Entity, EntityComponentManager, System};

use crate::{
    application::{Global, Tree},
    backend::Backend,
    properties::{Constraint, Margin, Padding},
    theme::{Selector, Theme},
};

/// This system is used to initializes the widgets.
pub struct InitSystem {
    pub backend: Rc<RefCell<dyn Backend>>,
}

impl InitSystem {
    // init css ids.
    fn init_id(&self, node: Entity, ecm: &mut EntityComponentManager) {
        // Add css id to global id map.
        let id = if let Ok(selector) = ecm.borrow_component::<Selector>(node) {
            if let Some(id) = &selector.id {
                Some((node, id.clone()))
            } else {
                None
            }
        } else {
            None
        };

        if let Some((entity, id)) = id {
            if let Ok(global) = ecm.borrow_mut_component::<Global>(0) {
                global.id_map.insert(id, entity);
            }
        }
    }

    // Read all initial data from css
    fn read_init_from_theme(&self, node: Entity, ecm: &mut EntityComponentManager, theme: &Theme) {
        let mut margin = Margin::default();
        let mut padding = Padding::default();
        let mut constraint = Constraint::default();

        // todo: update widget by selector method!!!

        if let Ok(selector) = ecm.borrow_component::<Selector>(node) {
            let pad = theme.uint("padding", selector) as i32;

            if pad > 0 {
                padding.left = pad;
                padding.top = pad;
                padding.right = pad;
                padding.bottom = pad;
            } else {
                padding.left = theme.uint("padding-left", selector) as i32;
                padding.top = theme.uint("padding-top", selector) as i32;
                padding.right = theme.uint("padding-right", selector) as i32;
                padding.bottom = theme.uint("padding-bottom", selector) as i32;
            }

            let mar = theme.uint("margin", selector) as i32;

            if mar > 0 {
                margin.left = mar;
                margin.top = mar;
                margin.right = mar;
                margin.bottom = mar;
            } else {
                margin.left = theme.uint("margin-left", selector) as i32;
                margin.top = theme.uint("margin-top", selector) as i32;
                margin.right = theme.uint("margin-right", selector) as i32;
                margin.bottom = theme.uint("margin-bottom", selector) as i32;
            }

            constraint.min_width = theme.uint("min-width", selector) as u32;
            constraint.max_width = theme.uint("max_width-width", selector) as u32;
            constraint.min_height = theme.uint("min_height-width", selector) as u32;
            constraint.max_height = theme.uint("min-max_height", selector) as u32;
            constraint.width = theme.uint("width", selector) as u32;
            constraint.height = theme.uint("height", selector) as u32;
        }

        ecm.register_component(node, padding);
        ecm.register_component(node, margin);
        ecm.register_component(node, constraint);
    }
}

impl System<Tree> for InitSystem {
    fn run(&self, tree: &Tree, ecm: &mut EntityComponentManager) {
        let mut backend = self.backend.borrow_mut();
        let context = backend.state_context();

        // init css ids
        for node in tree.into_iter() {
            self.init_id(node, ecm);
            self.read_init_from_theme(node, ecm, context.theme);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Exonum global variables which stored in blockchain as utf8 encoded json.

use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

/// Public keys of a validator.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    #[doc(hidden)]
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

/// Exonum blockchain global configuration.
/// This configuration must be same for any exonum node in the certain network on given height.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    /// Link to the previous configuration.
    /// For configuration in genesis block `hash` is just an array of zeroes.
    pub previous_cfg_hash: Hash,
    /// The height, starting from which this configuration becomes actual.
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    /// Consensus algorithm parameters.
    pub consensus: ConsensusConfig,
    /// Services specific variables.
    /// Keys are `service_name` from `Service` trait and values are the serialized json.
    pub services: BTreeMap<String, serde_json::Value>,
}

/// Consensus algorithm parameters.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    /// Interval between rounds.
    pub round_timeout: Milliseconds,
    /// Period of sending a Status message.
    pub status_timeout: Milliseconds,
    /// Peer exchange timeout.
    pub peers_timeout: Milliseconds,
    /// Proposal timeout after committing a block.
    pub propose_timeout: Milliseconds,
    /// Maximum number of transactions per block.
    pub txs_block_limit: u32,
    /// `TimeoutAdjuster` configuration.
    pub timeout_adjuster: TimeoutAdjusterConfig,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
            timeout_adjuster: TimeoutAdjusterConfig::Constant(500),
        }
    }
}

impl StoredConfiguration {
    /// Tries to serialize given configuration into the utf8 encoded json.
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    /// Tries to deserialize `StorageConfiguration` from the given utf8 encoded json.
    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in &config.validator_keys {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom(
                    "Duplicated keys are found: each consensus and service key must be unique",
                ));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn into_bytes(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn from_bytes(v: ::std::borrow::Cow<[u8]>) -> Self {
        StoredConfiguration::try_deserialize(v.as_ref()).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

/// `TimeoutAdjuster` config.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum TimeoutAdjusterConfig {
    /// Constant timeout adjuster config.
    Constant(Milliseconds),
    /// Dynamic timeout adjuster configuration.
    Dynamic {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Transactions threshold beginning from which adjuster returns minimal timeout.
        threshold: u32,
    },
    /// Moving average timeout adjuster configuration.
    MovingAverage {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Speed of the adjustment.
        adjustment_speed: f64,
        /// Optimal block load depending on the `txs_block_limit` from the `ConsensusConfig`.
        optimal_block_load: f64,
    },
}

#[cfg(test)]
mod tests {
    use toml;
    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Duplicated keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4)
            .map(|i| {
                ValidatorKeys {
                    consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                    service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
                }
            })
            .collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) {
        let serialized = configuration.try_serialize().unwrap();
        let _ = StoredConfiguration::try_deserialize(&serialized).unwrap();
    }
}
<commit_msg>Fix comment<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Exonum global variables which stored in blockchain as utf8 encoded json.

use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

/// Public keys of a validator.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    #[doc(hidden)]
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

/// Exonum blockchain global configuration.
/// This configuration must be same for any exonum node in the certain network on given height.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    /// Link to the previous configuration.
    /// For configuration in genesis block `hash` is just an array of zeroes.
    pub previous_cfg_hash: Hash,
    /// The height, starting from which this configuration becomes actual.
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    /// Consensus algorithm parameters.
    pub consensus: ConsensusConfig,
    /// Services specific variables.
    /// Keys are `service_name` from `Service` trait and values are the serialized json.
    pub services: BTreeMap<String, serde_json::Value>,
}

/// Consensus algorithm parameters.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    /// Interval between rounds.
    pub round_timeout: Milliseconds,
    /// Period of sending a Status message.
    pub status_timeout: Milliseconds,
    /// Peer exchange timeout.
    pub peers_timeout: Milliseconds,
    /// Proposal timeout after committing a block.
    pub propose_timeout: Milliseconds,
    /// Maximum number of transactions per block.
    pub txs_block_limit: u32,
    /// `TimeoutAdjuster` configuration.
    pub timeout_adjuster: TimeoutAdjusterConfig,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
            timeout_adjuster: TimeoutAdjusterConfig::Constant(500),
        }
    }
}

impl StoredConfiguration {
    /// Tries to serialize given configuration into the utf8 encoded json.
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    /// Tries to deserialize `StorageConfiguration` from the given utf8 encoded json.
    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in &config.validator_keys {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom(
                    "Duplicated keys are found: each consensus and service key must be unique",
                ));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn into_bytes(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn from_bytes(v: ::std::borrow::Cow<[u8]>) -> Self {
        StoredConfiguration::try_deserialize(v.as_ref()).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

/// `TimeoutAdjuster` config.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum TimeoutAdjusterConfig {
    /// Constant timeout adjuster config.
    Constant(Milliseconds),
    /// Dynamic timeout adjuster configuration.
    Dynamic {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Transactions threshold starting from which the adjuster returns the minimal timeout.
        threshold: u32,
    },
    /// Moving average timeout adjuster configuration.
    MovingAverage {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Speed of the adjustment.
        adjustment_speed: f64,
        /// Optimal block load depending on the `txs_block_limit` from the `ConsensusConfig`.
        optimal_block_load: f64,
    },
}

#[cfg(test)]
mod tests {
    use toml;
    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Duplicated keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4)
            .map(|i| {
                ValidatorKeys {
                    consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                    service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
                }
            })
            .collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) {
        let serialized = configuration.try_serialize().unwrap();
        let _ = StoredConfiguration::try_deserialize(&serialized).unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(alloc_system)]
#![feature(integer_atomics)]
#![feature(ascii_ctype)]
// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

//hexadecimal colors aren't numbers
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
#[allow(unused_extern_crates)]
extern crate alloc_system;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
//extern crate serde;
//extern crate serde_json;
extern crate backtrace;
extern crate num;
extern crate base64;
extern crate sha2;
extern crate unicase;
extern crate app_dirs;
extern crate chashmap;
extern crate parking_lot;
extern crate time;
extern crate uuid;
extern crate lockless;
extern crate smallvec;
#[cfg(test)]
extern crate mockito;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;
#[cfg(test)]
pub mod licensing;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::prelude::Utc;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

// We'll put our errors in an `errors` module, and other modules in
// this crate will `use errors::*;` to get access to everything
// `error_chain!` creates.
#[allow(unused_doc_comment)]
mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types

    error_chain! {

//        errors{
//           LicenseCorrupted(msg: String) {
//                description("Please verify/reinstall license; license corrupt.")
//                display("Please verify/reinstall license; license corrupt: {}", msg)
//           }
//           RsaDecryptInputLargerThanModulus
//        }

    }
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with(env!("CARGO_PKG_NAME")))
}

<commit_msg>Fix build error<commit_after>#![feature(alloc_system)]
#![feature(integer_atomics)]
#![feature(ascii_ctype)]
// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

//hexadecimal colors aren't numbers
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
#[allow(unused_extern_crates)]
extern crate alloc_system;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
//extern crate serde;
//extern crate serde_json;
extern crate backtrace;
extern crate num;
extern crate base64;
extern crate sha2;
extern crate unicase;
extern crate app_dirs;
extern crate chashmap;
extern crate parking_lot;
extern crate time;
extern crate uuid;
extern crate lockless;
extern crate smallvec;
#[cfg(test)]
extern crate mockito;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;
#[cfg(test)]
pub mod licensing;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::prelude::Utc;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

// We'll put our errors in an `errors` module, and other modules in
// this crate will `use errors::*;` to get access to everything
// `error_chain!` creates.
#[allow(unused_doc_comment)]
mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types

    error_chain! {

        errors{
           LicenseCorrupted(msg: String) {
                description("Please verify/reinstall license; license corrupt.")
                display("Please verify/reinstall license; license corrupt: {}", msg)
           }
           RsaDecryptInputLargerThanModulus
        }

    }
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with(env!("CARGO_PKG_NAME")))
}

<|endoftext|>


<commit_before>//! Free functions to create `&[T]` and `&mut [T]`.

use crate::array;
use crate::ptr;

/// Forms a slice from a pointer and a length.
///
/// The `len` argument is the number of **elements**, not the number of bytes.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
///       for an example incorrectly not taking this into account.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be mutated for the duration
///   of lifetime `'a`, except inside an `UnsafeCell`.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// # Caveat
///
/// The lifetime for the returned slice is inferred from its usage. To
/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
/// source lifetime is safe in the context, such as by providing a helper
/// function taking the lifetime of a host value for the slice, or by explicit
/// annotation.
///
/// # Examples
///
/// ```
/// use std::slice;
///
/// // manifest a slice for a single element
/// let x = 42;
/// let ptr = &x as *const _;
/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
/// assert_eq!(slice[0], 42);
/// ```
///
/// ### Incorrect usage
///
/// The following `join_slices` function is **unsound** ⚠
///
/// ```rust,no_run
/// use std::slice;
///
/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
///     let fst_end = fst.as_ptr().wrapping_add(fst.len());
///     let snd_start = snd.as_ptr();
///     assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
///     unsafe {
///         // The assertion above ensures `fst` and `snd` are contiguous, but they might
///         // still be contained within _different allocated objects_, in which case
///         // creating this slice is undefined behavior.
///         slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
///     }
/// }
///
/// fn main() {
///     // `a` and `b` are different allocated objects...
///     let a = 42;
///     let b = 27;
///     // ... which may nevertheless be laid out contiguously in memory: | a | b |
///     let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
/// }
/// ```
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
    debug_check_data_len(data, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
    unsafe { &*ptr::slice_from_raw_parts(data, len) }
}

/// Performs the same functionality as [`from_raw_parts`], except that a
/// mutable slice is returned.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for both reads and writes for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be accessed through any other pointer
///   (not derived from the return value) for the duration of lifetime `'a`.
///   Both read and write accesses are forbidden.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
    debug_check_data_len(data as _, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
    unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}

// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
#[cfg(all(not(bootstrap), debug_assertions))]
#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
    fn rt_check<T>(data: *const T) {
        use crate::intrinsics::is_aligned_and_not_null;

        assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
    }

    const fn ctfe_check<T>(_data: *const T) {
        // It's impossible to check alignment in const fn.
        //
        // CTFE engine checks that the pointer is aligned and not null.
    }

    // SAFETY:
    // - `calling from_raw_parts[_mut]` with arguments that fail to fulfil checks made here is UB, so unless UB is already triggered this is noop
    // - CTFE makes the same checks as `rt_check`, so behavior change is not observable due to compilation error
    unsafe {
        crate::intrinsics::const_eval_select((data,), ctfe_check, rt_check);
    }

    assert!(
        crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
        "attempt to create slice covering at least half the address space"
    );
}

#[cfg(not(all(not(bootstrap), debug_assertions)))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_ref<T>(s: &T) -> &[T] {
    array::from_ref(s)
}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
    array::from_mut(s)
}
<commit_msg>Apply changes proposed in the review<commit_after>//! Free functions to create `&[T]` and `&mut [T]`.

use crate::array;
use crate::ptr;

/// Forms a slice from a pointer and a length.
///
/// The `len` argument is the number of **elements**, not the number of bytes.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
///       for an example incorrectly not taking this into account.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be mutated for the duration
///   of lifetime `'a`, except inside an `UnsafeCell`.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// # Caveat
///
/// The lifetime for the returned slice is inferred from its usage. To
/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
/// source lifetime is safe in the context, such as by providing a helper
/// function taking the lifetime of a host value for the slice, or by explicit
/// annotation.
///
/// # Examples
///
/// ```
/// use std::slice;
///
/// // manifest a slice for a single element
/// let x = 42;
/// let ptr = &x as *const _;
/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
/// assert_eq!(slice[0], 42);
/// ```
///
/// ### Incorrect usage
///
/// The following `join_slices` function is **unsound** ⚠
///
/// ```rust,no_run
/// use std::slice;
///
/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
///     let fst_end = fst.as_ptr().wrapping_add(fst.len());
///     let snd_start = snd.as_ptr();
///     assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
///     unsafe {
///         // The assertion above ensures `fst` and `snd` are contiguous, but they might
///         // still be contained within _different allocated objects_, in which case
///         // creating this slice is undefined behavior.
///         slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
///     }
/// }
///
/// fn main() {
///     // `a` and `b` are different allocated objects...
///     let a = 42;
///     let b = 27;
///     // ... which may nevertheless be laid out contiguously in memory: | a | b |
///     let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
/// }
/// ```
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
    debug_check_data_len(data, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
    unsafe { &*ptr::slice_from_raw_parts(data, len) }
}

/// Performs the same functionality as [`from_raw_parts`], except that a
/// mutable slice is returned.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for both reads and writes for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be accessed through any other pointer
///   (not derived from the return value) for the duration of lifetime `'a`.
///   Both read and write accesses are forbidden.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
    debug_check_data_len(data as _, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
    unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}

// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
#[cfg(all(not(bootstrap), debug_assertions))]
#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
    fn rt_check<T>(data: *const T) {
        use crate::intrinsics::is_aligned_and_not_null;

        assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
    }

    const fn noop<T>(_: *const T) {}

    // SAFETY:
    //
    // `rt_check` is just a debug assert to hint users that they are causing UB,
    // it is not required for safety (the safety must be guatanteed by
    // the `from_raw_parts[_mut]` caller).
    //
    // Since the checks are not required, we ignore them in CTFE as they can't
    // be done there (alignment does not make much sense there).
    unsafe {
        crate::intrinsics::const_eval_select((data,), noop, rt_check);
    }

    assert!(
        crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
        "attempt to create slice covering at least half the address space"
    );
}

#[cfg(not(all(not(bootstrap), debug_assertions)))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_ref<T>(s: &T) -> &[T] {
    array::from_ref(s)
}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
    array::from_mut(s)
}
<|endoftext|>


<commit_before>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::ops::Try;
use crate::result::Result;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    #[lang = "Ready"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    #[lang = "Pending"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Pending,
}

impl<T> Poll<T> {
    /// Changes the ready value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map<U, F>(self, f: F) -> Poll<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns `true` if this is `Poll::Ready`
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn is_ready(&self) -> bool {
        matches!(*self, Poll::Ready(_))
    }

    /// Returns `true` if this is `Poll::Pending`
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn is_pending(&self) -> bool {
        !self.is_ready()
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T, E> Poll<Option<Result<T, E>>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[unstable(feature = "poll_map", issue = "63514")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[unstable(feature = "poll_map", issue = "63514")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Result<T, E>> {
    type Ok = Poll<T>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
            Poll::Ready(Err(e)) => Err(e),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Err(e))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(Ok)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Option<Result<T, E>>> {
    type Ok = Poll<Option<T>>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => Err(e),
            Poll::Ready(None) => Ok(Poll::Ready(None)),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Some(Err(e)))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(|x| x.map(Ok))
    }
}
<commit_msg>Add documentation for `impl<T> From<T> for Poll<T>`<commit_after>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::ops::Try;
use crate::result::Result;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    #[lang = "Ready"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    #[lang = "Pending"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Pending,
}

impl<T> Poll<T> {
    /// Changes the ready value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map<U, F>(self, f: F) -> Poll<U>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns `true` if this is `Poll::Ready`
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn is_ready(&self) -> bool {
        matches!(*self, Poll::Ready(_))
    }

    /// Returns `true` if this is `Poll::Pending`
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn is_pending(&self) -> bool {
        !self.is_ready()
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T, E> Poll<Option<Result<T, E>>> {
    /// Changes the success value of this `Poll` with the closure provided.
    #[unstable(feature = "poll_map", issue = "63514")]
    pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Changes the error value of this `Poll` with the closure provided.
    #[unstable(feature = "poll_map", issue = "63514")]
    pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
    /// Convert to a `Ready` variant.
    ///
    /// # Example
    ///
    /// ```
    /// # use core::task::Poll;
    /// assert_eq!(Poll::from(true), Poll::Ready(true));
    /// ```
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Result<T, E>> {
    type Ok = Poll<T>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
            Poll::Ready(Err(e)) => Err(e),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Err(e))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(Ok)
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Option<Result<T, E>>> {
    type Ok = Poll<Option<T>>;
    type Error = E;

    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => Err(e),
            Poll::Ready(None) => Ok(Poll::Ready(None)),
            Poll::Pending => Ok(Poll::Pending),
        }
    }

    #[inline]
    fn from_error(e: Self::Error) -> Self {
        Poll::Ready(Some(Err(e)))
    }

    #[inline]
    fn from_ok(x: Self::Ok) -> Self {
        x.map(|x| x.map(Ok))
    }
}
<|endoftext|>


<commit_before>// min-llvm-version: 12.0
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target aarch64-unknown-linux-gnu
// needs-llvm-components: aarch64
// only-aarch64

#![crate_type = "rlib"]

use std::sync::atomic::{AtomicI32, Ordering::*};

pub fn compare_exchange(a: &AtomicI32) {
    // On AArch64 LLVM should outline atomic operations.
    // CHECK: __aarch64_cas4_relax
    let _ = a.compare_exchange(0, 10, Relaxed, Relaxed);
}
<commit_msg>Rollup merge of #89902 - rusticstuff:outline-atomics-linux-only, r=workingjubilee<commit_after>// min-llvm-version: 12.0
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target aarch64-unknown-linux-gnu
// needs-llvm-components: aarch64
// only-aarch64
// only-linux

#![crate_type = "rlib"]

use std::sync::atomic::{AtomicI32, Ordering::*};

pub fn compare_exchange(a: &AtomicI32) {
    // On AArch64 LLVM should outline atomic operations.
    // CHECK: __aarch64_cas4_relax
    let _ = a.compare_exchange(0, 10, Relaxed, Relaxed);
}
<|endoftext|>