<commit_before>use regex::Regex;
use std::io::{BufRead, Write};
use std::thread::sleep;
use std::time::Duration;

struct Event {
    is_alloc: bool,
    start: usize,
    len: usize,
}

fn main() {
    let re = Regex::new(r"^(alloc|dealloc)\[(\d+), \d+\] = 0x([0-9a-f]+) \(\d+ ptrs, \d+ bytes\)$")
        .unwrap();

    let mut events = Vec::new();
    for line in std::io::stdin().lock().lines() {
        if let Some(caps) = re.captures(&line.unwrap()) {
            let typ = caps.get(1).unwrap().as_str();
            let len = caps.get(2).unwrap().as_str().parse::<usize>().unwrap();
            let start = usize::from_str_radix(&caps.get(3).unwrap().as_str(), 16).unwrap();
            events.push(Event {
                is_alloc: typ == "alloc",
                start,
                len,
            });
        }
    }

    let count_alloc = events.iter().filter(|e| e.is_alloc).count();
    let count_dealloc = events.len() - count_alloc;
    let start = events.iter().map(|e| e.start).min().unwrap_or(0);
    let end = events.iter().map(|e| e.start + e.len).max().unwrap_or(0);
    let mut usage = 0;
    let peak = events
        .iter()
        .map(|e| {
            if e.is_alloc {
                usage += e.len;
            } else {
                usage -= e.len;
            }
            usage
        })
        .max()
        .unwrap_or(0);
    let len = end - start;
    println!(
        "Observed {} allocations and {} deallocations",
        count_alloc, count_dealloc
    );
    println!("Start address: {:08x}", start);
    println!("End address: {:08x}", end);
    println!("Peak usage: {0} = {0:08x} bytes", peak);
    println!("Peak consumption: {0} = {0:08x} bytes", len);
    println!("Fragmentation overhead: {0} = {0:08x} bytes", len - peak);

    print!("\nLoading visualization");
    for _ in 0..30 {
        print!(".");
        std::io::stdout().flush().unwrap();
        sleep(Duration::from_millis(50));
    }
    println!();

    let window = ncurses::initscr();
    ncurses::cbreak();
    ncurses::noecho();
    ncurses::intrflush(window, false);
    ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);

    let width = ncurses::getmaxx(window) as usize;

    for e in events.iter() {
        let position = e.start - start;
        ncurses::wmove(window, (position / width) as i32, (position % width) as i32);

        let mut s = Vec::with_capacity(e.len);
        if e.is_alloc {
            s.resize(e.len, b'#');
        } else {
            s.resize(e.len, b'.');
        }
        ncurses::addstr(std::str::from_utf8(s.as_slice()).unwrap());
        ncurses::refresh();
        sleep(Duration::from_millis(50));
    }

    ncurses::endwin();
}
<commit_msg>Address review comments.<commit_after>// Copyright 2020 Google LLC
//
// 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.

use regex::Regex;
use std::io::{BufRead, Write};
use std::thread::sleep;
use std::time::Duration;

/// An allocation or deallocation event.
struct Event {
    /// Whether this even is an allocation (true) or a deallocation (false).
    is_alloc: bool,
    /// The start address of the (de)allocated block, in bytes.
    start: usize,
    /// The length of the (de)allocated block, in bytes.
    len: usize,
}

fn main() {
    /// The following regex matches lines looking like the following from OpenSK's output. Such
    /// lines are printed to the console when the `--debug-allocations` feature is enabled in the
    /// deploy script.
    ///
    /// ```
    /// alloc[256, 1] = 0x2002410c (2 ptrs, 384 bytes)
    /// dealloc[256, 1] = 0x2002410c (1 ptrs, 512 bytes)
    /// ```
    ///
    /// The two integers between square brackets after the (de)alloc keywords represent the length
    /// and alignement of the allocated block, respectively. The integer serialized in hexadecimal
    /// after the equal sign represents the starting address of the allocated block. The two
    /// integers within parentheses represent statistics about the total number of allocated blocks
    /// and the total number of allocated bytes after the (de)allocation operation, respectively.
    ///
    /// This regex captures three elements, in this order.
    /// - The keyword to know whether this operation is an allocation or a deallocation.
    /// - The length of the allocated block.
    /// - The starting address of the allocated block.
    let re = Regex::new(r"^(alloc|dealloc)\[(\d+), \d+\] = 0x([0-9a-f]+) \(\d+ ptrs, \d+ bytes\)$")
        .unwrap();

    let mut events = Vec::new();
    for line in std::io::stdin().lock().lines() {
        if let Some(caps) = re.captures(&line.unwrap()) {
            let typ = caps.get(1).unwrap().as_str();
            let len = caps.get(2).unwrap().as_str().parse::<usize>().unwrap();
            let start = usize::from_str_radix(&caps.get(3).unwrap().as_str(), 16).unwrap();
            events.push(Event {
                is_alloc: typ == "alloc",
                start,
                len,
            });
        }
    }

    let count_alloc = events.iter().filter(|e| e.is_alloc).count();
    let count_dealloc = events.len() - count_alloc;
    let start = events.iter().map(|e| e.start).min().unwrap_or(0);
    let end = events.iter().map(|e| e.start + e.len).max().unwrap_or(0);
    let mut usage = 0;
    let peak = events
        .iter()
        .map(|e| {
            if e.is_alloc {
                usage += e.len;
            } else {
                usage -= e.len;
            }
            usage
        })
        .max()
        .unwrap_or(0);
    let len = end - start;
    println!(
        "Observed {} allocations and {} deallocations",
        count_alloc, count_dealloc
    );
    println!("Start address: {:08x}", start);
    println!("End address: {:08x}", end);
    println!("Peak usage: {0} = {0:08x} bytes", peak);
    println!("Peak consumption: {0} = {0:08x} bytes", len);
    println!("Fragmentation overhead: {0} = {0:08x} bytes", len - peak);

    print!("\nLoading visualization");
    for _ in 0..30 {
        print!(".");
        std::io::stdout().flush().unwrap();
        sleep(Duration::from_millis(50));
    }
    println!();

    let window = ncurses::initscr();
    ncurses::cbreak();
    ncurses::noecho();
    ncurses::intrflush(window, false);
    ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);

    let width = ncurses::getmaxx(window) as usize;

    for e in events.iter() {
        let position = e.start - start;
        ncurses::wmove(window, (position / width) as i32, (position % width) as i32);

        let mut s = Vec::with_capacity(e.len);
        if e.is_alloc {
            s.resize(e.len, b'#');
        } else {
            s.resize(e.len, b'.');
        }
        ncurses::addstr(std::str::from_utf8(s.as_slice()).unwrap());
        ncurses::refresh();
        sleep(Duration::from_millis(50));
    }

    ncurses::endwin();
}
<|endoftext|>


<commit_before>use std;
use glfw;

import glfw::*;

fn main ()
{
	unsafe {

	if (glfwInit() == 0)
	{
		fail("glfwInit() failed\n");
	}

	if (glfwOpenWindow(800, 600, 5, 6, 5, 0, 0, 0, GLFW_WINDOW) == 0)
	{
		fail("glfwOpenWindow() failed\n");
	}

	let major : int = 0;
	let minor : int = 0;
	let rev : int = 0;
	glfwGetGLVersion(ptr::addr_of(major), ptr::addr_of(minor), ptr::addr_of(rev));

	let title = #fmt("Opengl version - %d.%d rev %d", major, minor, rev);
	glfwSetWindowTitle(title);

	let done = false;

	while (!done)
	{
		if (glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS  || !glfwGetWindowParam(GLFW_OPENED) as bool)
		{
		  break;
		}

		glfwSwapBuffers();
    }

	glfwTerminate();

	}  //unsafe
}
<commit_msg>	modified:   glfw_example.rs 	Tidy up<commit_after>use std;
use glfw;

import glfw::*;

fn main ()
{
	unsafe {

	if (glfwInit() == 0)
	{
		fail("glfwInit() failed\n");
	}

	if (glfwOpenWindow(800, 600, 5, 6, 5, 0, 0, 0, GLFW_WINDOW) == 0)
	{
		fail("glfwOpenWindow() failed\n");
	}

	let major : int = 0;
	let minor : int = 0;
	let rev : int = 0;
	glfwGetGLVersion(ptr::addr_of(major), ptr::addr_of(minor), ptr::addr_of(rev));

	let title = #fmt("Opengl version - %d.%d rev %d", major, minor, rev);
	glfwSetWindowTitle(title);

	while (true)
	{
		if (glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS  || !glfwGetWindowParam(GLFW_OPENED) as bool)
		{
            break;
		}

		glfwSwapBuffers();
    }

	glfwTerminate();

	}  //unsafe
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher, SipHasher};

pub fn name_hash(str_: &str) -> u64 {
    let mut hasher = SipHasher::new();
    str_.hash(&mut hasher);
    hasher.finish()
}

pub trait NameTableIdx {
    fn to_index(&self) -> usize;
}

impl NameTableIdx for usize {
    fn to_index(&self) -> usize {
        *self
    }
}

pub trait NameTable {
    fn parent<'a>(&'a self) -> Option<&'a NameTable>;

    fn initial_local(&self) -> usize;
    fn len_local(&self) -> usize;
    fn at_local<'a>(&'a self, idx: usize) -> &'a str;
    fn find_local(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }

    fn len(&self) -> usize {
        return self.len_local() + self.parent().map_or(0usize, |parent_table| parent_table.len());
    }

    fn at<'a>(&'a self, idx: usize) -> &'a str {
        let initial = self.initial_local();
        if idx >= initial {
            return self.at_local(idx - initial);
        } else if let Some(parent_table) = self.parent().as_ref() {
            &parent_table.at(idx)
        } else {
            panic!("access out of bound");
        }
    }

    fn find(&self, name: &str) -> Option<usize> {
        let initial = self.initial_local();
        self.find_local(name).map(|idx| idx + initial).or_else(|| {
            if let Some(parent_table) = self.parent().as_ref() {
                return parent_table.find(name);
            }
            return None;
        })
    }
}

pub struct StaticNameTable {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    parent: Option<Box<NameTable>>,
}

impl NameTable for StaticNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }
}

impl StaticNameTable {
    pub fn new(names_: &'static str, name_offsets_: &'static [usize]) -> Self {
        return StaticNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     parent: ParentTableType)
                                                     -> Self {
        return StaticNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            parent: Some(Box::new(parent)),
        };
    }

}

pub struct DynamicNameTable {
    initial_idx: usize,
    names: Box<Vec<String>>,
    parent: Option<Box<NameTable>>,
}

impl NameTable for DynamicNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.names.len()
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        self.names[idx].as_str()
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }
}

impl DynamicNameTable {
    pub fn new() -> Self {
        return DynamicNameTable {
            initial_idx: 0usize,
            names: Box::new(Vec::new()),
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(parent: ParentTableType) -> Self {
        return DynamicNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: Box::new(Vec::new()),
            parent: Some(Box::new(parent)),
        };
    }

    pub fn intern(&mut self, name: &str) -> usize {
        self.find(name)
            .or_else(|| {
                Some({
                    self.names.as_mut().push(name.to_owned());
                    self.initial_idx + self.names.len() - 1
                })
            })
            .unwrap()
    }

}

pub struct StaticHashedNameTable {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    hash_idxes: &'static [(u64, usize)],
    parent: Option<Box<NameTable>>,
}

impl StaticHashedNameTable {
    pub fn new(names_: &'static str,
               name_offsets_: &'static [usize],
               hash_idxes_: &'static [(u64, usize)])
               -> Self {

        return StaticHashedNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     hash_idxes_: &'static [(u64, usize)],
                                                     parent: ParentTableType)
                                                     -> Self {

        return StaticHashedNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: Some(Box::new(parent)),
        };
    }

    pub fn index<'x, T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }

    fn hash_enabled(&self) -> bool {
        self.hash_idxes.len() != 0
    }

    fn find_local_hashing(&self, name: &str) -> Option<usize> {
        let target = name_hash(name);
        let result = self.hash_idxes.binary_search_by(|&(a, _)| a.cmp(&target));
        match result {
            Ok(val) => {
                if self.at_local(self.hash_idxes[val].1) == name {
                    Some(self.hash_idxes[val].1)
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    fn find_local_fallback(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }
}

impl NameTable for StaticHashedNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }

    fn find_local(&self, name: &str) -> Option<usize> {
        if self.hash_enabled() {
            self.find_local_hashing(name)
        } else {
            self.find_local_fallback(name)
        }
    }
}

use std::ops::Index;

impl<T: NameTableIdx> Index<T> for NameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}

impl<T: NameTableIdx> Index<T> for StaticNameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}

impl<T: NameTableIdx> Index<T> for DynamicNameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}

impl<T: NameTableIdx> Index<T> for StaticHashedNameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}<commit_msg>Remove deprecated SipHasher.<commit_after>use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;

pub fn name_hash(str_: &str) -> u64 {
    let mut hasher = DefaultHasher::new();
    str_.hash(&mut hasher);
    hasher.finish()
}

pub trait NameTableIdx {
    fn to_index(&self) -> usize;
}

impl NameTableIdx for usize {
    fn to_index(&self) -> usize {
        *self
    }
}

pub trait NameTable {
    fn parent<'a>(&'a self) -> Option<&'a NameTable>;

    fn initial_local(&self) -> usize;
    fn len_local(&self) -> usize;
    fn at_local<'a>(&'a self, idx: usize) -> &'a str;
    fn find_local(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }

    fn len(&self) -> usize {
        return self.len_local() + self.parent().map_or(0usize, |parent_table| parent_table.len());
    }

    fn at<'a>(&'a self, idx: usize) -> &'a str {
        let initial = self.initial_local();
        if idx >= initial {
            return self.at_local(idx - initial);
        } else if let Some(parent_table) = self.parent().as_ref() {
            &parent_table.at(idx)
        } else {
            panic!("access out of bound");
        }
    }

    fn find(&self, name: &str) -> Option<usize> {
        let initial = self.initial_local();
        self.find_local(name).map(|idx| idx + initial).or_else(|| {
            if let Some(parent_table) = self.parent().as_ref() {
                return parent_table.find(name);
            }
            return None;
        })
    }
}

pub struct StaticNameTable {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    parent: Option<Box<NameTable>>,
}

impl NameTable for StaticNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }
}

impl StaticNameTable {
    pub fn new(names_: &'static str, name_offsets_: &'static [usize]) -> Self {
        return StaticNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     parent: ParentTableType)
                                                     -> Self {
        return StaticNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            parent: Some(Box::new(parent)),
        };
    }

}

pub struct DynamicNameTable {
    initial_idx: usize,
    names: Box<Vec<String>>,
    parent: Option<Box<NameTable>>,
}

impl NameTable for DynamicNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.names.len()
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        self.names[idx].as_str()
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }
}

impl DynamicNameTable {
    pub fn new() -> Self {
        return DynamicNameTable {
            initial_idx: 0usize,
            names: Box::new(Vec::new()),
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(parent: ParentTableType) -> Self {
        return DynamicNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: Box::new(Vec::new()),
            parent: Some(Box::new(parent)),
        };
    }

    pub fn intern(&mut self, name: &str) -> usize {
        self.find(name)
            .or_else(|| {
                Some({
                    self.names.as_mut().push(name.to_owned());
                    self.initial_idx + self.names.len() - 1
                })
            })
            .unwrap()
    }

}

pub struct StaticHashedNameTable {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    hash_idxes: &'static [(u64, usize)],
    parent: Option<Box<NameTable>>,
}

impl StaticHashedNameTable {
    pub fn new(names_: &'static str,
               name_offsets_: &'static [usize],
               hash_idxes_: &'static [(u64, usize)])
               -> Self {

        return StaticHashedNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     hash_idxes_: &'static [(u64, usize)],
                                                     parent: ParentTableType)
                                                     -> Self {

        return StaticHashedNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: Some(Box::new(parent)),
        };
    }

    pub fn index<'x, T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }

    fn hash_enabled(&self) -> bool {
        self.hash_idxes.len() != 0
    }

    fn find_local_hashing(&self, name: &str) -> Option<usize> {
        let target = name_hash(name);
        let result = self.hash_idxes.binary_search_by(|&(a, _)| a.cmp(&target));
        match result {
            Ok(val) => {
                if self.at_local(self.hash_idxes[val].1) == name {
                    Some(self.hash_idxes[val].1)
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    fn find_local_fallback(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }
}

impl NameTable for StaticHashedNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }

    fn find_local(&self, name: &str) -> Option<usize> {
        if self.hash_enabled() {
            self.find_local_hashing(name)
        } else {
            self.find_local_fallback(name)
        }
    }
}

use std::ops::Index;

impl<T: NameTableIdx> Index<T> for NameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}

impl<T: NameTableIdx> Index<T> for StaticNameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}

impl<T: NameTableIdx> Index<T> for DynamicNameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}

impl<T: NameTableIdx> Index<T> for StaticHashedNameTable {
    type Output = str;

    fn index<'a>(&'a self, _index: T) -> &'a str {
        self.at(_index.to_index())
    }
}<|endoftext|>


<commit_before>struct Container(i32, i32);

// 这个 trait 检查 2 个项是否存到 Container（容器）中。
// 还会获得第一个值或最后一个值。
trait Contains {
    // 在这里定义可以被方法利用的泛型类型。
    type A;
    type B;

    fn contains(&self, &Self::A, &Self::B) -> bool;
    fn first(&self) -> i32;
    fn last(&self) -> i32;
}

impl Contains for Container {
    // 指出 `A` 和 `B` 是什么类型。如果 `input`（输入）类型
    // 为 `Container(i32, i32)`，那么 `output`（输出）类型
    // 会被确定为 `i32` 和 `i32`。
    type A = i32;
    type B = i32;

    // `&Self::A` 和 `&self::B` 在这里也是有效的。
    fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
        (&self.0 == number_1) && (&self.1 == number_2)
    }

    // 得到第一个数字。
    fn first(&self) -> i32 { self.0 }

    // 得到最后一个数字。
    fn last(&self) -> i32 { self.1 }
}

fn difference<C: Contains>(container: &C) -> i32 {
    container.last() - container.first()
}

fn main() {
    let number_1 = 3;
    let number_2 = 10;

    let container = Container(number_1, number_2);

    println!("Does container contain {} and {}: {}",
        &number_1, &number_2,
        container.contains(&number_1, &number_2));
    println!("First number: {}", container.first());
    println!("Last number: {}", container.last());

    println!("The difference is: {}", difference(&container));
}
<commit_msg>generics/assoc_items/types: Fix typo in comment<commit_after>struct Container(i32, i32);

// 这个 trait 检查 2 个项是否存到 Container（容器）中。
// 还会获得第一个值或最后一个值。
trait Contains {
    // 在这里定义可以被方法利用的泛型类型。
    type A;
    type B;

    fn contains(&self, &Self::A, &Self::B) -> bool;
    fn first(&self) -> i32;
    fn last(&self) -> i32;
}

impl Contains for Container {
    // 指出 `A` 和 `B` 是什么类型。如果 `input`（输入）类型
    // 为 `Container(i32, i32)`，那么 `output`（输出）类型
    // 会被确定为 `i32` 和 `i32`。
    type A = i32;
    type B = i32;

    // `&Self::A` 和 `&Self::B` 在这里也是有效的。
    fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
        (&self.0 == number_1) && (&self.1 == number_2)
    }

    // 得到第一个数字。
    fn first(&self) -> i32 { self.0 }

    // 得到最后一个数字。
    fn last(&self) -> i32 { self.1 }
}

fn difference<C: Contains>(container: &C) -> i32 {
    container.last() - container.first()
}

fn main() {
    let number_1 = 3;
    let number_2 = 10;

    let container = Container(number_1, number_2);

    println!("Does container contain {} and {}: {}",
        &number_1, &number_2,
        container.contains(&number_1, &number_2));
    println!("First number: {}", container.first());
    println!("Last number: {}", container.last());

    println!("The difference is: {}", difference(&container));
}
<|endoftext|>


<commit_before>use command::{Command, Query};
use commandlinable::Escape;

#[derive(Clone, Debug)]
pub struct CommandLine {
    command: Command,
    arguments: Query,
}

impl CommandLine {
    pub fn new(command: Command, query: Query) -> CommandLine {
        CommandLine {
            command: command,
            arguments: query,
        }
    }

    /// Get command enum constant to construct command line query.
    pub fn get_command(&mut self) -> Command {
        self.command.clone()
    }

    /// Get vectorize `("key", "value")` pairs to construct command line query.
    pub fn get_argument(&mut self) -> Query {
        self.arguments.clone()
    }

    /// Set vectorize `("key", "value")` pairs to construct command line query.
    pub fn set_argument(&mut self, arguments: Query) {
        self.arguments = arguments
    }

    /// Create command line style command query.
    ///
    /// `vec![("key","value")]` interprets to `"--key value"`.
    /// And two or more value pair are concatinate with ` `(a space).
    pub fn make_command(&mut self) -> String {
        let mut output = String::new();
        for query in self.arguments.to_owned() {
            let (key, value) = query;
            if output.len() > 0 {
                output.push_str(" ");
            }
            let format_string = format!("--{} {}", &*key, Escape(&*value));
            output.push_str(format_string.as_str());
        }
        output
    }

    ///
    /// Create Groonga command line style command.
    pub fn encode(&mut self) -> String {
        format!("{} {}", self.get_command(), self.make_command())
            .trim()
            .to_string()
    }
}

#[cfg(test)]
mod test {
    use super::CommandLine;
    use select::SelectCommand;
    use load::{LoadCommand, InputType};
    use status::StatusCommand;
    use dump::DumpCommand;
    use delete::DeleteCommand;
    use table_create::TableCreateCommand;
    use types::table_flag_type::TableFlagType;
    use column_create::ColumnCreateCommand;
    use types::data_type::DataType;

    #[test]
    fn test_select() {
        let (command, query) = SelectCommand::new("Test".to_string())
                                   .filter("output_column @ \"type_safe\"".to_string())
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "select --table Test --filter \'output_column @ \"type_safe\"\'";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_load() {
        let load_data: &'static str = r#"[
{"_key":"http://example.org/","title":"This is test record 1!"},
]"#;
        let (command, query, values) = LoadCommand::new("Test".to_string(), load_data.to_string())
                                           .input_type(InputType::Json)
                                           .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "load --table Test --input_type json";
        assert_eq!(cli_encoded.to_string(), command.encode());
        assert_eq!(load_data.to_string(), values);
    }

    #[test]
    fn test_status() {
        let (command, query) = StatusCommand::new().build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "status";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_dump() {
        let (command, query) = DumpCommand::new()
                                   .tables(vec!["Books".to_string(), "Categories".to_string()])
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "dump --tables Books,Categories";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_delete() {
        let (command, query) = DeleteCommand::new("Books".to_string())
                                   .filter("author == unknown".to_string())
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "delete --table Books --filter \'author == unknown\'";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_table_create() {
        let (command, query) = TableCreateCommand::new("Test".to_string())
                                   .flags(vec![(TableFlagType::PatKey),
                                               (TableFlagType::KeyWithSIS)])
                                   .build();
        let mut command = CommandLine::new(command, query);
        let url_encoded = "table_create --name Test --flags TABLE_PAT_KEY|KEY_WITH_SIS";
        assert_eq!(url_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_column_create() {
        let (command, query) = ColumnCreateCommand::new("Test".to_string(), "element".to_string())
                                   .column_type(DataType::LongText)
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "column_create --table Test --name element --type LongText";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }
}
<commit_msg>Suppress a length comparison with zero clippy warning<commit_after>use command::{Command, Query};
use commandlinable::Escape;

#[derive(Clone, Debug)]
pub struct CommandLine {
    command: Command,
    arguments: Query,
}

impl CommandLine {
    pub fn new(command: Command, query: Query) -> CommandLine {
        CommandLine {
            command: command,
            arguments: query,
        }
    }

    /// Get command enum constant to construct command line query.
    pub fn get_command(&mut self) -> Command {
        self.command.clone()
    }

    /// Get vectorize `("key", "value")` pairs to construct command line query.
    pub fn get_argument(&mut self) -> Query {
        self.arguments.clone()
    }

    /// Set vectorize `("key", "value")` pairs to construct command line query.
    pub fn set_argument(&mut self, arguments: Query) {
        self.arguments = arguments
    }

    /// Create command line style command query.
    ///
    /// `vec![("key","value")]` interprets to `"--key value"`.
    /// And two or more value pair are concatinate with ` `(a space).
    pub fn make_command(&mut self) -> String {
        let mut output = String::new();
        for query in self.arguments.to_owned() {
            let (key, value) = query;
            if output.len() >= 1 {
                output.push_str(" ");
            }
            let format_string = format!("--{} {}", &*key, Escape(&*value));
            output.push_str(format_string.as_str());
        }
        output
    }

    ///
    /// Create Groonga command line style command.
    pub fn encode(&mut self) -> String {
        format!("{} {}", self.get_command(), self.make_command())
            .trim()
            .to_string()
    }
}

#[cfg(test)]
mod test {
    use super::CommandLine;
    use select::SelectCommand;
    use load::{LoadCommand, InputType};
    use status::StatusCommand;
    use dump::DumpCommand;
    use delete::DeleteCommand;
    use table_create::TableCreateCommand;
    use types::table_flag_type::TableFlagType;
    use column_create::ColumnCreateCommand;
    use types::data_type::DataType;

    #[test]
    fn test_select() {
        let (command, query) = SelectCommand::new("Test".to_string())
                                   .filter("output_column @ \"type_safe\"".to_string())
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "select --table Test --filter \'output_column @ \"type_safe\"\'";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_load() {
        let load_data: &'static str = r#"[
{"_key":"http://example.org/","title":"This is test record 1!"},
]"#;
        let (command, query, values) = LoadCommand::new("Test".to_string(), load_data.to_string())
                                           .input_type(InputType::Json)
                                           .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "load --table Test --input_type json";
        assert_eq!(cli_encoded.to_string(), command.encode());
        assert_eq!(load_data.to_string(), values);
    }

    #[test]
    fn test_status() {
        let (command, query) = StatusCommand::new().build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "status";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_dump() {
        let (command, query) = DumpCommand::new()
                                   .tables(vec!["Books".to_string(), "Categories".to_string()])
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "dump --tables Books,Categories";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_delete() {
        let (command, query) = DeleteCommand::new("Books".to_string())
                                   .filter("author == unknown".to_string())
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "delete --table Books --filter \'author == unknown\'";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_table_create() {
        let (command, query) = TableCreateCommand::new("Test".to_string())
                                   .flags(vec![(TableFlagType::PatKey),
                                               (TableFlagType::KeyWithSIS)])
                                   .build();
        let mut command = CommandLine::new(command, query);
        let url_encoded = "table_create --name Test --flags TABLE_PAT_KEY|KEY_WITH_SIS";
        assert_eq!(url_encoded.to_string(), command.encode());
    }

    #[test]
    fn test_column_create() {
        let (command, query) = ColumnCreateCommand::new("Test".to_string(), "element".to_string())
                                   .column_type(DataType::LongText)
                                   .build();
        let mut command = CommandLine::new(command, query);
        let cli_encoded = "column_create --table Test --name element --type LongText";
        assert_eq!(cli_encoded.to_string(), command.encode());
    }
}
<|endoftext|>


<commit_before>//! Base trait and common functionalities for all consumers.
extern crate rdkafka_sys as rdkafka;

pub mod base_consumer;
pub mod stream_consumer;

use self::rdkafka::types::*;

use std::ptr;
use std::os::raw::c_void;
use util::cstr_to_owned;

use client::{Context, NativeClient};
use message::Message;
use metadata::Metadata;
use error::KafkaResult;

pub use consumer::base_consumer::BaseConsumer;
pub use topic_partition_list::TopicPartitionList;

/// Consumer specific Context. This user-defined object can be used to provide custom callbacks to
/// consumer events. Refer to the list of methods to check which callbacks can be specified.
pub trait ConsumerContext: Context {
    /// Implements the default rebalancing strategy and calls the pre_rebalance and
    /// post_rebalance methods. If this method is overridden, it will be responsibility
    /// of the user to call them if needed.
    fn rebalance(&self,
                 native_client: &NativeClient,
                 err: RDKafkaRespErr,
                 partitions_ptr: *mut RDKafkaTopicPartitionList) {

        let rebalance = match err {
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => {
                // TODO: this might be expensive
                let topic_partition_list = TopicPartitionList::from_rdkafka(partitions_ptr);
                Rebalance::Assign(topic_partition_list)
            },
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS => {
                Rebalance::Revoke
            },
            _ => {
                let error = unsafe { cstr_to_owned(rdkafka::rd_kafka_err2str(err)) };
                error!("Error rebalancing: {}", error);
                Rebalance::Error(error)
            }
        };

        self.pre_rebalance(&rebalance);

        // Execute rebalance
        unsafe {
            match err {
                RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => {
                    rdkafka::rd_kafka_assign(native_client.ptr(), partitions_ptr);
                },
                RDKafkaRespErr::RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS => {
                    rdkafka::rd_kafka_assign(native_client.ptr(), ptr::null());
                },
                _ => {
                    rdkafka::rd_kafka_assign(native_client.ptr(), ptr::null());
                }
            }
        }
        self.post_rebalance(&rebalance);
    }

    /// Pre-rebalance callback. This method will run before the rebalance, and it will receive the
    /// relabance information. This method is executed as part of the rebalance callback and should
    /// terminate its execution quickly.
    fn pre_rebalance(&self, _rebalance: &Rebalance) { }

    /// Post-rebalance callback. This method will run before the rebalance, and it will receive the
    /// relabance information. This method is executed as part of the rebalance callback and should
    /// terminate its execution quickly.
    fn post_rebalance(&self, _rebalance: &Rebalance) { }
}

#[derive(Clone)]
struct EmptyConsumerContext;

impl Context for EmptyConsumerContext { }
impl ConsumerContext for EmptyConsumerContext { }

/// Contains rebalance information.
#[derive(Clone, Debug)]
pub enum Rebalance {
    Assign(TopicPartitionList),
    Revoke,
    Error(String)
}

/// Native rebalance callback. This callback will run on every rebalance, and it will call the
/// rebalance method defined in the current `Context`.
unsafe extern "C" fn rebalance_cb<C: ConsumerContext>(rk: *mut RDKafka,
                                                          err: RDKafkaRespErr,
                                                          partitions: *mut RDKafkaTopicPartitionList,
                                                          opaque_ptr: *mut c_void) {
    let context: &C = &*(opaque_ptr as *const C);
    let native_client = NativeClient::new(rk);

    context.rebalance(&native_client, err, partitions);
}

/// Specifies if the commit should be performed synchronously
/// or asynchronously.
pub enum CommitMode {
    /// Synchronous commit.
    Sync,
    /// Asynchronous commit.
    Async,
}

/// Common trait for all consumers
pub trait Consumer<C: ConsumerContext> {
    /// Returns a reference to the BaseConsumer.
    fn get_base_consumer(&self) -> &BaseConsumer<C>;
    /// Returns a mutable reference to the BaseConsumer.
    fn get_base_consumer_mut(&mut self) -> &mut BaseConsumer<C>;

    // Default implementations

    /// Subscribe the consumer to a list of topics.
    fn subscribe(&mut self, topics: &Vec<&str>) -> KafkaResult<()> {
        self.get_base_consumer_mut().subscribe(topics)
    }

    /// Manually assign topics and partitions to the consumer.
    fn assign(&mut self, assignment: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer_mut().assign(assignment)
    }

    /// Commit a specific message. If mode is set to CommitMode::Sync,
    /// the call will block until the message has been succesfully
    /// committed.
    fn commit_message(&self, message: &Message, mode: CommitMode) {
        self.get_base_consumer().commit_message(message, mode);
    }

    /// Returns the metadata information of the entire cluster for all the topics in the cluster.
    fn fetch_metadata(&mut self, timeout_ms: i32) -> KafkaResult<Metadata> {
        self.get_base_consumer().fetch_metadata(timeout_ms)
    }
}
<commit_msg>Make EmptyConsumerContext public<commit_after>//! Base trait and common functionalities for all consumers.
extern crate rdkafka_sys as rdkafka;

pub mod base_consumer;
pub mod stream_consumer;

use self::rdkafka::types::*;

use std::ptr;
use std::os::raw::c_void;
use util::cstr_to_owned;

use client::{Context, NativeClient};
use message::Message;
use metadata::Metadata;
use error::KafkaResult;

pub use consumer::base_consumer::BaseConsumer;
pub use topic_partition_list::TopicPartitionList;

/// Consumer specific Context. This user-defined object can be used to provide custom callbacks to
/// consumer events. Refer to the list of methods to check which callbacks can be specified.
pub trait ConsumerContext: Context {
    /// Implements the default rebalancing strategy and calls the pre_rebalance and
    /// post_rebalance methods. If this method is overridden, it will be responsibility
    /// of the user to call them if needed.
    fn rebalance(&self,
                 native_client: &NativeClient,
                 err: RDKafkaRespErr,
                 partitions_ptr: *mut RDKafkaTopicPartitionList) {

        let rebalance = match err {
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => {
                // TODO: this might be expensive
                let topic_partition_list = TopicPartitionList::from_rdkafka(partitions_ptr);
                Rebalance::Assign(topic_partition_list)
            },
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS => {
                Rebalance::Revoke
            },
            _ => {
                let error = unsafe { cstr_to_owned(rdkafka::rd_kafka_err2str(err)) };
                error!("Error rebalancing: {}", error);
                Rebalance::Error(error)
            }
        };

        self.pre_rebalance(&rebalance);

        // Execute rebalance
        unsafe {
            match err {
                RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => {
                    rdkafka::rd_kafka_assign(native_client.ptr(), partitions_ptr);
                },
                RDKafkaRespErr::RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS => {
                    rdkafka::rd_kafka_assign(native_client.ptr(), ptr::null());
                },
                _ => {
                    rdkafka::rd_kafka_assign(native_client.ptr(), ptr::null());
                }
            }
        }
        self.post_rebalance(&rebalance);
    }

    /// Pre-rebalance callback. This method will run before the rebalance, and it will receive the
    /// relabance information. This method is executed as part of the rebalance callback and should
    /// terminate its execution quickly.
    fn pre_rebalance(&self, _rebalance: &Rebalance) { }

    /// Post-rebalance callback. This method will run before the rebalance, and it will receive the
    /// relabance information. This method is executed as part of the rebalance callback and should
    /// terminate its execution quickly.
    fn post_rebalance(&self, _rebalance: &Rebalance) { }
}

#[derive(Clone)]
pub struct EmptyConsumerContext;

impl Context for EmptyConsumerContext { }
impl ConsumerContext for EmptyConsumerContext { }

/// Contains rebalance information.
#[derive(Clone, Debug)]
pub enum Rebalance {
    Assign(TopicPartitionList),
    Revoke,
    Error(String)
}

/// Native rebalance callback. This callback will run on every rebalance, and it will call the
/// rebalance method defined in the current `Context`.
unsafe extern "C" fn rebalance_cb<C: ConsumerContext>(rk: *mut RDKafka,
                                                          err: RDKafkaRespErr,
                                                          partitions: *mut RDKafkaTopicPartitionList,
                                                          opaque_ptr: *mut c_void) {
    let context: &C = &*(opaque_ptr as *const C);
    let native_client = NativeClient::new(rk);

    context.rebalance(&native_client, err, partitions);
}

/// Specifies if the commit should be performed synchronously
/// or asynchronously.
pub enum CommitMode {
    /// Synchronous commit.
    Sync,
    /// Asynchronous commit.
    Async,
}

/// Common trait for all consumers
pub trait Consumer<C: ConsumerContext> {
    /// Returns a reference to the BaseConsumer.
    fn get_base_consumer(&self) -> &BaseConsumer<C>;
    /// Returns a mutable reference to the BaseConsumer.
    fn get_base_consumer_mut(&mut self) -> &mut BaseConsumer<C>;

    // Default implementations

    /// Subscribe the consumer to a list of topics.
    fn subscribe(&mut self, topics: &Vec<&str>) -> KafkaResult<()> {
        self.get_base_consumer_mut().subscribe(topics)
    }

    /// Manually assign topics and partitions to the consumer.
    fn assign(&mut self, assignment: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer_mut().assign(assignment)
    }

    /// Commit a specific message. If mode is set to CommitMode::Sync,
    /// the call will block until the message has been succesfully
    /// committed.
    fn commit_message(&self, message: &Message, mode: CommitMode) {
        self.get_base_consumer().commit_message(message, mode);
    }

    /// Returns the metadata information of the entire cluster for all the topics in the cluster.
    fn fetch_metadata(&mut self, timeout_ms: i32) -> KafkaResult<Metadata> {
        self.get_base_consumer().fetch_metadata(timeout_ms)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::collections::HashMap;
use std::path::Path;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError};
use std::thread;
use std::time::Duration;

use butterfly;
use common::ui::UI;
use depot_client;
use hcore::package::{PackageIdent, PackageInstall};
use hcore::service::ServiceGroup;
use hcore::crypto::default_cache_key_path;
use hcore::fs::{CACHE_ARTIFACT_PATH, FS_ROOT_PATH};
use time::{SteadyTime, Duration as TimeDuration};

use {PRODUCT, VERSION};
use error::Result;
use manager::census::CensusList;
use manager::service::{Service, Topology, UpdateStrategy};

static LOGKEY: &'static str = "SU";
const UPDATE_STRATEGY_FREQUENCY_MS: i64 = 60_000;

type UpdaterStateList = HashMap<ServiceGroup, UpdaterState>;

enum UpdaterState {
    AtOnce(Receiver<PackageInstall>),
    Rolling(RollingState),
}

enum RollingState {
    AwaitingElection,
    InElection,
    Leader(LeaderState),
    Follower(FollowerState),
}

enum LeaderState {
    Polling(Receiver<PackageInstall>),
    Waiting,
}

enum FollowerState {
    Waiting,
    Updating(Receiver<PackageInstall>),
}

pub struct ServiceUpdater {
    states: UpdaterStateList,
    butterfly: butterfly::Server,
}

impl ServiceUpdater {
    pub fn new(butterfly: butterfly::Server) -> Self {
        ServiceUpdater {
            states: UpdaterStateList::default(),
            butterfly: butterfly,
        }
    }

    pub fn add(&mut self, service: &Service) -> bool {
        match service.update_strategy {
            UpdateStrategy::None => false,
            UpdateStrategy::AtOnce => {
                self.states
                    .entry(service.service_group.clone())
                    .or_insert_with(|| {
                                        let rx = Worker::new(service)
                                            .start(&service.service_group, None);
                                        UpdaterState::AtOnce(rx)
                                    });
                true
            }
            UpdateStrategy::Rolling => {
                self.states
                    .entry(service.service_group.clone())
                    .or_insert(UpdaterState::Rolling(RollingState::AwaitingElection));
                true
            }
        }
    }

    pub fn check_for_updated_package(&mut self,
                                     service: &mut Service,
                                     census_list: &CensusList)
                                     -> bool {
        let mut updated = false;
        match self.states.get_mut(&service.service_group) {
            Some(&mut UpdaterState::AtOnce(ref mut rx)) => {
                match rx.try_recv() {
                    Ok(package) => {
                        service.update_package(package);
                        return true;
                    }
                    Err(TryRecvError::Empty) => return false,
                    Err(TryRecvError::Disconnected) => {}
                }
                outputln!(preamble service.service_group,
                    "Service Updater worker has died {}", "; restarting...");
                *rx = Worker::new(service).start(&service.service_group, None);
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::AwaitingElection)) => {
                if let Some(census) = census_list.get(&*service.service_group) {
                    if service.topology == Topology::Leader {
                        debug!("Rolling Update, determining proper suitability because we're in \
                                a leader topology");
                        match (census.me(), census.get_leader()) {
                            (Some(me), Some(leader)) => {
                                let suitability = if me == leader {
                                    u64::min_value()
                                } else {
                                    u64::max_value()
                                };
                                self.butterfly
                                    .start_update_election(service.service_group.clone(),
                                                           suitability,
                                                           0);
                                *st = RollingState::InElection
                            }
                            _ => return false,
                        }
                    } else {
                        debug!("Rolling update, using default suitability");
                        self.butterfly
                            .start_update_election(service.service_group.clone(), 0, 0);
                        *st = RollingState::InElection;
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::InElection)) => {
                if let Some(census) = census_list.get(&*service.service_group) {
                    match (census.me(), census.get_update_leader()) {
                        (Some(me), Some(leader)) => {
                            if me == leader {
                                debug!("We're the leader");
                                // Start in waiting state to ensure all members agree with our
                                // version before attempting a new rolling upgrade.
                                *st = RollingState::Leader(LeaderState::Waiting);
                            } else {
                                debug!("We're a follower");
                                *st = RollingState::Follower(FollowerState::Waiting);
                            }
                        }
                        (Some(_), None) => return false,
                        _ => return false,
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Leader(ref mut state))) => {
                match *state {
                    LeaderState::Polling(ref mut rx) => {
                        match rx.try_recv() {
                            Ok(package) => {
                                debug!("Rolling Update, polling found a new package");
                                service.update_package(package);
                                updated = true;
                            }
                            Err(TryRecvError::Empty) => return false,
                            Err(TryRecvError::Disconnected) => {
                                outputln!(preamble service.service_group,
                                    "Service Updater has died {}", "; restarting...");
                                *rx = Worker::new(service).start(&service.service_group, None);
                            }
                        }
                    }
                    LeaderState::Waiting => {
                        match census_list.get(&*service.service_group) {
                            Some(census) => {
                                if census
                                       .members_ordered()
                                       .iter()
                                       .any(|ce| {
                                                ce.pkg.as_ref().unwrap() !=
                                                census.me().unwrap().pkg.as_ref().unwrap()
                                            }) {
                                    debug!("Update leader still waiting for followers...");
                                    return false;
                                }
                                let rx = Worker::new(service).start(&service.service_group, None);
                                *state = LeaderState::Polling(rx);
                            }
                            None => {
                                panic!("Expected census list to have service group '{}'!",
                                       &*service.service_group)
                            }
                        }
                    }
                }
                if updated {
                    *state = LeaderState::Waiting;
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Follower(ref mut state))) => {
                match *state {
                    FollowerState::Waiting => {
                        match census_list.get(&*service.service_group) {
                            Some(census) => {
                                match (census.get_update_leader(),
                                       census.previous_peer(),
                                       census.me()) {
                                    (Some(leader), Some(peer), Some(me)) => {
                                        if leader.pkg == me.pkg {
                                            debug!("We're not in an update");
                                            return false;
                                        }
                                        if leader.pkg != peer.pkg {
                                            debug!("We're in an update but it's not our turn");
                                            return false;
                                        }
                                        debug!("We're in an update and it's our turn");
                                        let rx =
                                            Worker::new(service).start(&service.service_group,
                                                                       leader.pkg.clone());
                                        *state = FollowerState::Updating(rx);
                                    }
                                    _ => return false,
                                }
                            }
                            None => {
                                panic!("Expected census list to have service group '{}'!",
                                       &*service.service_group)
                            }
                        }
                    }
                    FollowerState::Updating(ref mut rx) => {
                        match census_list.get(&*service.service_group) {
                            Some(census) => {
                                match rx.try_recv() {
                                    Ok(package) => {
                                        service.update_package(package);
                                        updated = true
                                    }
                                    Err(TryRecvError::Empty) => return false,
                                    Err(TryRecvError::Disconnected) => {
                                        outputln!(preamble service.service_group,
                                            "Service Updater has died {}", "; restarting...");
                                        let package =
                                            census.get_update_leader().unwrap().pkg.clone();
                                        *rx = Worker::new(service).start(&service.service_group,
                                                                         package);
                                    }
                                }
                            }
                            None => {
                                panic!("Expected census list to have service group '{}'!",
                                       &*service.service_group)
                            }
                        }
                    }
                }
                if updated {
                    *state = FollowerState::Waiting;
                }
            }
            None => {}
        }
        updated
    }
}

struct Worker {
    current: PackageIdent,
    spec_ident: PackageIdent,
    depot: depot_client::Client,
    ui: UI,
}

impl Worker {
    pub fn new(service: &Service) -> Self {
        Worker {
            current: service.package().ident().clone(),
            spec_ident: service.spec_ident.clone(),
            depot: depot_client::Client::new(&service.depot_url, PRODUCT, VERSION, None).unwrap(),
            ui: UI::default(),
        }
    }

    /// Start a new update worker.
    ///
    /// Passing an optional package identifier will make the worker perform a run-once update to
    /// retrieve a specific version from a remote Depot. If no package identifier is specified,
    /// then the updater will poll until a newer more suitable package is found.
    pub fn start(mut self,
                 sg: &ServiceGroup,
                 ident: Option<PackageIdent>)
                 -> Receiver<PackageInstall> {
        let (tx, rx) = sync_channel(0);
        thread::Builder::new()
            .name(format!("service-updater-{}", sg))
            .spawn(move || match ident {
                       Some(latest) => self.run_once(tx, latest),
                       None => self.run_poll(tx),
                   })
            .expect("unable to start service-updater thread");
        rx
    }

    fn run_once(&mut self, sender: SyncSender<PackageInstall>, ident: PackageIdent) {
        outputln!("Updating from {} to {}", self.current, ident);
        loop {
            let next_check = SteadyTime::now() +
                             TimeDuration::milliseconds(UPDATE_STRATEGY_FREQUENCY_MS);
            match self.install(&ident, true) {
                Ok(package) => {
                    self.current = package.ident().clone();
                    sender.send(package).expect("Main thread has gone away!");
                    break;
                }
                Err(e) => warn!("Failed to install updated package: {:?}", e),
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn run_poll(&mut self, sender: SyncSender<PackageInstall>) {
        loop {
            let next_check = SteadyTime::now() +
                             TimeDuration::milliseconds(UPDATE_STRATEGY_FREQUENCY_MS);
            match self.depot.show_package(&self.spec_ident) {
                Ok(remote) => {
                    let latest: PackageIdent = remote.get_ident().clone().into();
                    if latest > self.current {
                        outputln!("Updating from {} to {}", self.current, latest);
                        match self.install(&latest, true) {
                            Ok(package) => {
                                self.current = latest;
                                sender.send(package).expect("Main thread has gone away!");
                                break;
                            }
                            Err(e) => warn!("Failed to install updated package: {:?}", e),
                        }
                    } else {
                        info!("Package found is not newer than ours");
                    }
                }
                Err(e) => warn!("Updater failed to get latest package: {:?}", e),
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn install(&mut self, package: &PackageIdent, recurse: bool) -> Result<PackageInstall> {
        let package = match PackageInstall::load(package, Some(&*FS_ROOT_PATH)) {
            Ok(pkg) => pkg,
            Err(_) => try!(self.download(package)),
        };
        if recurse {
            for ident in package.tdeps()?.iter() {
                try!(self.install(&ident, false));
            }
        }
        Ok(package)
    }

    fn download(&mut self, package: &PackageIdent) -> Result<PackageInstall> {
        outputln!("Downloading {}", package);
        let mut archive = try!(self.depot
                                   .fetch_package(package,
                                                  &Path::new(&*FS_ROOT_PATH)
                                                       .join(CACHE_ARTIFACT_PATH),
                                                  self.ui.progress()));
        try!(archive.verify(&default_cache_key_path(None)));
        outputln!("Installing {}", package);
        try!(archive.unpack(None));
        let pkg = PackageInstall::load(archive.ident().as_ref().unwrap(), Some(&*FS_ROOT_PATH))?;
        Ok(pkg)
    }
}
<commit_msg>Remove redundant pub and dead code from components/sup/src/manager/service_updater.rs<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

use std::collections::HashMap;
use std::path::Path;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError};
use std::thread;
use std::time::Duration;

use butterfly;
use common::ui::UI;
use depot_client;
use hcore::package::{PackageIdent, PackageInstall};
use hcore::service::ServiceGroup;
use hcore::crypto::default_cache_key_path;
use hcore::fs::{CACHE_ARTIFACT_PATH, FS_ROOT_PATH};
use time::{SteadyTime, Duration as TimeDuration};

use {PRODUCT, VERSION};
use error::Result;
use manager::census::CensusList;
use manager::service::{Service, Topology, UpdateStrategy};

static LOGKEY: &'static str = "SU";
const UPDATE_STRATEGY_FREQUENCY_MS: i64 = 60_000;

type UpdaterStateList = HashMap<ServiceGroup, UpdaterState>;

enum UpdaterState {
    AtOnce(Receiver<PackageInstall>),
    Rolling(RollingState),
}

enum RollingState {
    AwaitingElection,
    InElection,
    Leader(LeaderState),
    Follower(FollowerState),
}

enum LeaderState {
    Polling(Receiver<PackageInstall>),
    Waiting,
}

enum FollowerState {
    Waiting,
    Updating(Receiver<PackageInstall>),
}

pub struct ServiceUpdater {
    states: UpdaterStateList,
    butterfly: butterfly::Server,
}

impl ServiceUpdater {
    pub fn new(butterfly: butterfly::Server) -> Self {
        ServiceUpdater {
            states: UpdaterStateList::default(),
            butterfly: butterfly,
        }
    }

    pub fn add(&mut self, service: &Service) -> bool {
        match service.update_strategy {
            UpdateStrategy::None => false,
            UpdateStrategy::AtOnce => {
                self.states
                    .entry(service.service_group.clone())
                    .or_insert_with(|| {
                                        let rx = Worker::new(service)
                                            .start(&service.service_group, None);
                                        UpdaterState::AtOnce(rx)
                                    });
                true
            }
            UpdateStrategy::Rolling => {
                self.states
                    .entry(service.service_group.clone())
                    .or_insert(UpdaterState::Rolling(RollingState::AwaitingElection));
                true
            }
        }
    }

    pub fn check_for_updated_package(&mut self,
                                     service: &mut Service,
                                     census_list: &CensusList)
                                     -> bool {
        let mut updated = false;
        match self.states.get_mut(&service.service_group) {
            Some(&mut UpdaterState::AtOnce(ref mut rx)) => {
                match rx.try_recv() {
                    Ok(package) => {
                        service.update_package(package);
                        return true;
                    }
                    Err(TryRecvError::Empty) => return false,
                    Err(TryRecvError::Disconnected) => {}
                }
                outputln!(preamble service.service_group,
                    "Service Updater worker has died {}", "; restarting...");
                *rx = Worker::new(service).start(&service.service_group, None);
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::AwaitingElection)) => {
                if let Some(census) = census_list.get(&*service.service_group) {
                    if service.topology == Topology::Leader {
                        debug!("Rolling Update, determining proper suitability because we're in \
                                a leader topology");
                        match (census.me(), census.get_leader()) {
                            (Some(me), Some(leader)) => {
                                let suitability = if me == leader {
                                    u64::min_value()
                                } else {
                                    u64::max_value()
                                };
                                self.butterfly
                                    .start_update_election(service.service_group.clone(),
                                                           suitability,
                                                           0);
                                *st = RollingState::InElection
                            }
                            _ => return false,
                        }
                    } else {
                        debug!("Rolling update, using default suitability");
                        self.butterfly
                            .start_update_election(service.service_group.clone(), 0, 0);
                        *st = RollingState::InElection;
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(ref mut st @ RollingState::InElection)) => {
                if let Some(census) = census_list.get(&*service.service_group) {
                    match (census.me(), census.get_update_leader()) {
                        (Some(me), Some(leader)) => {
                            if me == leader {
                                debug!("We're the leader");
                                // Start in waiting state to ensure all members agree with our
                                // version before attempting a new rolling upgrade.
                                *st = RollingState::Leader(LeaderState::Waiting);
                            } else {
                                debug!("We're a follower");
                                *st = RollingState::Follower(FollowerState::Waiting);
                            }
                        }
                        (Some(_), None) => return false,
                        _ => return false,
                    }
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Leader(ref mut state))) => {
                match *state {
                    LeaderState::Polling(ref mut rx) => {
                        match rx.try_recv() {
                            Ok(package) => {
                                debug!("Rolling Update, polling found a new package");
                                service.update_package(package);
                                updated = true;
                            }
                            Err(TryRecvError::Empty) => return false,
                            Err(TryRecvError::Disconnected) => {
                                outputln!(preamble service.service_group,
                                    "Service Updater has died {}", "; restarting...");
                                *rx = Worker::new(service).start(&service.service_group, None);
                            }
                        }
                    }
                    LeaderState::Waiting => {
                        match census_list.get(&*service.service_group) {
                            Some(census) => {
                                if census
                                       .members_ordered()
                                       .iter()
                                       .any(|ce| {
                                                ce.pkg.as_ref().unwrap() !=
                                                census.me().unwrap().pkg.as_ref().unwrap()
                                            }) {
                                    debug!("Update leader still waiting for followers...");
                                    return false;
                                }
                                let rx = Worker::new(service).start(&service.service_group, None);
                                *state = LeaderState::Polling(rx);
                            }
                            None => {
                                panic!("Expected census list to have service group '{}'!",
                                       &*service.service_group)
                            }
                        }
                    }
                }
                if updated {
                    *state = LeaderState::Waiting;
                }
            }
            Some(&mut UpdaterState::Rolling(RollingState::Follower(ref mut state))) => {
                match *state {
                    FollowerState::Waiting => {
                        match census_list.get(&*service.service_group) {
                            Some(census) => {
                                match (census.get_update_leader(),
                                       census.previous_peer(),
                                       census.me()) {
                                    (Some(leader), Some(peer), Some(me)) => {
                                        if leader.pkg == me.pkg {
                                            debug!("We're not in an update");
                                            return false;
                                        }
                                        if leader.pkg != peer.pkg {
                                            debug!("We're in an update but it's not our turn");
                                            return false;
                                        }
                                        debug!("We're in an update and it's our turn");
                                        let rx =
                                            Worker::new(service).start(&service.service_group,
                                                                       leader.pkg.clone());
                                        *state = FollowerState::Updating(rx);
                                    }
                                    _ => return false,
                                }
                            }
                            None => {
                                panic!("Expected census list to have service group '{}'!",
                                       &*service.service_group)
                            }
                        }
                    }
                    FollowerState::Updating(ref mut rx) => {
                        match census_list.get(&*service.service_group) {
                            Some(census) => {
                                match rx.try_recv() {
                                    Ok(package) => {
                                        service.update_package(package);
                                        updated = true
                                    }
                                    Err(TryRecvError::Empty) => return false,
                                    Err(TryRecvError::Disconnected) => {
                                        outputln!(preamble service.service_group,
                                            "Service Updater has died {}", "; restarting...");
                                        let package =
                                            census.get_update_leader().unwrap().pkg.clone();
                                        *rx = Worker::new(service).start(&service.service_group,
                                                                         package);
                                    }
                                }
                            }
                            None => {
                                panic!("Expected census list to have service group '{}'!",
                                       &*service.service_group)
                            }
                        }
                    }
                }
                if updated {
                    *state = FollowerState::Waiting;
                }
            }
            None => {}
        }
        updated
    }
}

struct Worker {
    current: PackageIdent,
    spec_ident: PackageIdent,
    depot: depot_client::Client,
    ui: UI,
}

impl Worker {
    fn new(service: &Service) -> Self {
        Worker {
            current: service.package().ident().clone(),
            spec_ident: service.spec_ident.clone(),
            depot: depot_client::Client::new(&service.depot_url, PRODUCT, VERSION, None).unwrap(),
            ui: UI::default(),
        }
    }

    /// Start a new update worker.
    ///
    /// Passing an optional package identifier will make the worker perform a run-once update to
    /// retrieve a specific version from a remote Depot. If no package identifier is specified,
    /// then the updater will poll until a newer more suitable package is found.
    fn start(mut self, sg: &ServiceGroup, ident: Option<PackageIdent>) -> Receiver<PackageInstall> {
        let (tx, rx) = sync_channel(0);
        thread::Builder::new()
            .name(format!("service-updater-{}", sg))
            .spawn(move || match ident {
                       Some(latest) => self.run_once(tx, latest),
                       None => self.run_poll(tx),
                   })
            .expect("unable to start service-updater thread");
        rx
    }

    fn run_once(&mut self, sender: SyncSender<PackageInstall>, ident: PackageIdent) {
        outputln!("Updating from {} to {}", self.current, ident);
        loop {
            let next_check = SteadyTime::now() +
                             TimeDuration::milliseconds(UPDATE_STRATEGY_FREQUENCY_MS);
            match self.install(&ident, true) {
                Ok(package) => {
                    self.current = package.ident().clone();
                    sender.send(package).expect("Main thread has gone away!");
                    break;
                }
                Err(e) => warn!("Failed to install updated package: {:?}", e),
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn run_poll(&mut self, sender: SyncSender<PackageInstall>) {
        loop {
            let next_check = SteadyTime::now() +
                             TimeDuration::milliseconds(UPDATE_STRATEGY_FREQUENCY_MS);
            match self.depot.show_package(&self.spec_ident) {
                Ok(remote) => {
                    let latest: PackageIdent = remote.get_ident().clone().into();
                    if latest > self.current {
                        outputln!("Updating from {} to {}", self.current, latest);
                        match self.install(&latest, true) {
                            Ok(package) => {
                                self.current = latest;
                                sender.send(package).expect("Main thread has gone away!");
                                break;
                            }
                            Err(e) => warn!("Failed to install updated package: {:?}", e),
                        }
                    } else {
                        info!("Package found is not newer than ours");
                    }
                }
                Err(e) => warn!("Updater failed to get latest package: {:?}", e),
            }
            let time_to_wait = (next_check - SteadyTime::now()).num_milliseconds();
            if time_to_wait > 0 {
                thread::sleep(Duration::from_millis(time_to_wait as u64));
            }
        }
    }

    fn install(&mut self, package: &PackageIdent, recurse: bool) -> Result<PackageInstall> {
        let package = match PackageInstall::load(package, Some(&*FS_ROOT_PATH)) {
            Ok(pkg) => pkg,
            Err(_) => try!(self.download(package)),
        };
        if recurse {
            for ident in package.tdeps()?.iter() {
                try!(self.install(&ident, false));
            }
        }
        Ok(package)
    }

    fn download(&mut self, package: &PackageIdent) -> Result<PackageInstall> {
        outputln!("Downloading {}", package);
        let mut archive = try!(self.depot
                                   .fetch_package(package,
                                                  &Path::new(&*FS_ROOT_PATH)
                                                       .join(CACHE_ARTIFACT_PATH),
                                                  self.ui.progress()));
        try!(archive.verify(&default_cache_key_path(None)));
        outputln!("Installing {}", package);
        try!(archive.unpack(None));
        let pkg = PackageInstall::load(archive.ident().as_ref().unwrap(), Some(&*FS_ROOT_PATH))?;
        Ok(pkg)
    }
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg};

fn main() {

    // Option arguments are those that take an additional value, such as "-c value". In clap they
    // support three types of specification, those with short() as "-o some", or those with long()
    // as "--option value" or "--option=value"
    //
    // Options also support a multiple setting, which is discussed in the example below.
    let matches = App::new("MyApp")
                        // Regular App configuration goes here...

                        // Assume we an application that accepts an input file via the "-i file"
                        // or the "--input file" (as well as "--input=file").
                        // Below every setting supported by option arguments is discussed.
                        // NOTE: You DO NOT need to specify each setting, only those which apply
                        // to your particular case.
                        .arg(Arg::with_name("input")
                                    .help("the input file to use") // Displayed when showing help info
                                    .takes_value(true)             // MUST be set to true in order to be an "option" argument
                                    .short("i")                    // This argument is triggered with "-i"
                                    .long("input")                 // This argument is triggered with "--input"
                                    .multiple(true)                // Set to true if you wish to allow multiple occurrences
                                                                   // such as "-i file -i other_file -i third_file"
                                    .required(true)                // By default this argument MUST be present
                                                                   // NOTE: mutual exclusions take precedence over
                                                                   // required arguments
                                    .requires("config")            // Says, "If the user uses "input", they MUST
                                                                   // also use this other 'config' arg too"
                                                                   // Can also specifiy a list using
                                                                   // requires_all(Vec<&str>)
                                    .conflicts_with("output")      // Opposite of requires(), says "if the
                                                                   // user uses -a, they CANNOT use 'output'"
                                                                   // also has a conflicts_with_all(Vec<&str>)
                        )
                        // NOTE: In order to compile this example, comment out conflicts_with()
                        // and requires() because we have not defined an "output" or "config"
                        // argument.
                        .get_matches();

    // We can find out whether or not "input" was used
    if matches.is_present("input") {
        println!("An input file was specified");
    }

    // We can also get the value for "input"
    //
    // NOTE: If we specified multiple(), this will only return the _FIRST_
    // occurrence
    if let Some(ref in_file) = matches.value_of("input") {
        println!("An input file: {}", in_file);
    }

    // If we specified the multiple() setting we can get all the values
    if let Some(in_v) = matches.values_of("input") {
        for in_file in in_v {
            println!("An input file: {}", in_file);
        }
    }

    // We can see how many times the option was used with the occurrences_of() method
    //
    // NOTE: Just like with flags, if we did not specify the multiple() setting this will only
    // return 1 no matter how many times the argument was used (unless it wasn't used at all, in
    // in which case 0 is returned)
    println!("The \"input\" argument was used {} times", matches.occurrences_of("input"));

    // Continued program logic goes here...
}
<commit_msg>Fix typo in 07_option_args.rs<commit_after>extern crate clap;

use clap::{App, Arg};

fn main() {

    // Option arguments are those that take an additional value, such as "-c value". In clap they
    // support three types of specification, those with short() as "-o some", or those with long()
    // as "--option value" or "--option=value"
    //
    // Options also support a multiple setting, which is discussed in the example below.
    let matches = App::new("MyApp")
                        // Regular App configuration goes here...

                        // Assume we have an application that accepts an input file via the "-i file"
                        // or the "--input file" (as well as "--input=file").
                        // Below every setting supported by option arguments is discussed.
                        // NOTE: You DO NOT need to specify each setting, only those which apply
                        // to your particular case.
                        .arg(Arg::with_name("input")
                                    .help("the input file to use") // Displayed when showing help info
                                    .takes_value(true)             // MUST be set to true in order to be an "option" argument
                                    .short("i")                    // This argument is triggered with "-i"
                                    .long("input")                 // This argument is triggered with "--input"
                                    .multiple(true)                // Set to true if you wish to allow multiple occurrences
                                                                   // such as "-i file -i other_file -i third_file"
                                    .required(true)                // By default this argument MUST be present
                                                                   // NOTE: mutual exclusions take precedence over
                                                                   // required arguments
                                    .requires("config")            // Says, "If the user uses "input", they MUST
                                                                   // also use this other 'config' arg too"
                                                                   // Can also specifiy a list using
                                                                   // requires_all(Vec<&str>)
                                    .conflicts_with("output")      // Opposite of requires(), says "if the
                                                                   // user uses -a, they CANNOT use 'output'"
                                                                   // also has a conflicts_with_all(Vec<&str>)
                        )
                        // NOTE: In order to compile this example, comment out conflicts_with()
                        // and requires() because we have not defined an "output" or "config"
                        // argument.
                        .get_matches();

    // We can find out whether or not "input" was used
    if matches.is_present("input") {
        println!("An input file was specified");
    }

    // We can also get the value for "input"
    //
    // NOTE: If we specified multiple(), this will only return the _FIRST_
    // occurrence
    if let Some(ref in_file) = matches.value_of("input") {
        println!("An input file: {}", in_file);
    }

    // If we specified the multiple() setting we can get all the values
    if let Some(in_v) = matches.values_of("input") {
        for in_file in in_v {
            println!("An input file: {}", in_file);
        }
    }

    // We can see how many times the option was used with the occurrences_of() method
    //
    // NOTE: Just like with flags, if we did not specify the multiple() setting this will only
    // return 1 no matter how many times the argument was used (unless it wasn't used at all, in
    // in which case 0 is returned)
    println!("The \"input\" argument was used {} times", matches.occurrences_of("input"));

    // Continued program logic goes here...
}
<|endoftext|>