<commit_before>//! Types used in this bot implementation.

use errors::CommandParseError;

#[derive(Debug, Clone)]
pub struct Command {
    pub name: String,
    pub params: Vec<String>,
}

/// Parse a text message, return a command if possible
impl<'a> ::conv::TryFrom<&'a str> for Command {
    type Err = CommandParseError;
    fn try_from(text: &'a str) -> Result<Self, CommandParseError> {

        // Verify if this is actually a command
        if !text.starts_with("/") {
            return Err(CommandParseError::NoCommand);
        }

        // Split text into words iterator
        let mut words = text.split(' ');

        // Parse out name and params
        if let Some(name) = words.next() {
            let params: Vec<String> = words.map(|s| s.into()).collect();
            Ok(Command {
                name: name.into(),
                params: params,
            })
        } else {
            Err(CommandParseError::NoCommand)
        }
    }
}
<commit_msg>Remove slash from type name<commit_after>//! Types used in this bot implementation.

use errors::CommandParseError;

#[derive(Debug, Clone)]
pub struct Command {
    pub name: String,
    pub params: Vec<String>,
}

/// Parse a text message, return a command if possible
impl<'a> ::conv::TryFrom<&'a str> for Command {
    type Err = CommandParseError;
    fn try_from(text: &'a str) -> Result<Self, CommandParseError> {

        // Verify if this is actually a command
        if !text.starts_with("/") {
            return Err(CommandParseError::NoCommand);
        }

        // Split text into words iterator
        let mut words = text.split(' ');

        // Parse out name and params
        if let Some(name) = words.next() {
            let params: Vec<String> = words.map(|s| s.into()).collect();
            Ok(Command {
                name: name[1..].into(),
                params: params,
            })
        } else {
            Err(CommandParseError::NoCommand)
        }
    }
}
<|endoftext|>


<commit_before>//! Types that specify what is contained in a ZIP.

use time;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum System
{
    Dos = 0,
    Unix = 3,
    Unknown,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl System {
    pub fn from_u8(system: u8) -> System
    {
        use self::System::*;

        match system {
            0 => Dos,
            3 => Unix,
            _ => Unknown,
        }
    }
}

pub const DEFAULT_VERSION: u8 = 46;

/// Structure representing a ZIP file.
#[derive(Debug, Clone)]
pub struct ZipFileData
{
    /// Compatibility of the file attribute information
    pub system: System,
    /// Specification version
    pub version_made_by: u8,
    /// True if the file is encrypted.
    pub encrypted: bool,
    /// Compression method used to store the file
    pub compression_method: ::compression::CompressionMethod,
    /// Last modified time. This will only have a 2 second precision.
    pub last_modified_time: time::Tm,
    /// CRC32 checksum
    pub crc32: u32,
    /// Size of the file in the ZIP
    pub compressed_size: u64,
    /// Size of the file when extracted
    pub uncompressed_size: u64,
    /// Name of the file
    pub file_name: String,
    /// Raw file name. To be used when file_name was incorrectly decoded.
    pub file_name_raw: Vec<u8>,
    /// File comment
    pub file_comment: String,
    /// Specifies where the local header of the file starts
    pub header_start: u64,
    /// Specifies where the compressed data of the file starts
    pub data_start: u64,
    /// External file attributes
    pub external_attributes: u32,
}

impl ZipFileData {
    pub fn file_name_sanitized(&self) -> ::std::path::PathBuf {
        let no_null_filename = match self.file_name.find('\0') {
            Some(index) => &self.file_name[0..index],
            None => &self.file_name,
        };

        ::std::path::Path::new(no_null_filename)
            .components()
            .filter(|component| match *component {
                ::std::path::Component::Normal(..) => true,
                _ => false,
            })
            .fold(::std::path::PathBuf::new(), |mut path, ref cur| {
                path.push(cur.as_os_str());
                path
            })
    }

    pub fn version_needed(&self) -> u16 {
        match self.compression_method {
            #[cfg(feature = "bzip2")]
            ::compression::CompressionMethod::Bzip2 => 46,
            _ => 20,
        }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn system() {
        use super::System;
        assert_eq!(System::Dos as u16, 0u16);
        assert_eq!(System::Unix as u16, 3u16);
        assert_eq!(System::from_u8(0), System::Dos);
        assert_eq!(System::from_u8(3), System::Unix);
    }

    #[test]
    fn sanitize() {
        use super::*;
        let file_name = "/path/../../../../etc/./passwd\0/etc/shadow".to_string();
        let data = ZipFileData {
            system: System::Dos,
            version_made_by: 0,
            encrypted: false,
            compression_method: ::compression::CompressionMethod::Stored,
            last_modified_time: time::empty_tm(),
            crc32: 0,
            compressed_size: 0,
            uncompressed_size: 0,
            file_name: file_name.clone(),
            file_name_raw: file_name.into_bytes(),
            file_comment: String::new(),
            header_start: 0,
            data_start: 0,
            external_attributes: 0,
        };
        assert_eq!(data.file_name_sanitized(), ::std::path::PathBuf::from("path/etc/passwd"));
    }
}
<commit_msg>Fix file name sanitization for incompatible path separators.<commit_after>//! Types that specify what is contained in a ZIP.

use time;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum System
{
    Dos = 0,
    Unix = 3,
    Unknown,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl System {
    pub fn from_u8(system: u8) -> System
    {
        use self::System::*;

        match system {
            0 => Dos,
            3 => Unix,
            _ => Unknown,
        }
    }
}

pub const DEFAULT_VERSION: u8 = 46;

/// Structure representing a ZIP file.
#[derive(Debug, Clone)]
pub struct ZipFileData
{
    /// Compatibility of the file attribute information
    pub system: System,
    /// Specification version
    pub version_made_by: u8,
    /// True if the file is encrypted.
    pub encrypted: bool,
    /// Compression method used to store the file
    pub compression_method: ::compression::CompressionMethod,
    /// Last modified time. This will only have a 2 second precision.
    pub last_modified_time: time::Tm,
    /// CRC32 checksum
    pub crc32: u32,
    /// Size of the file in the ZIP
    pub compressed_size: u64,
    /// Size of the file when extracted
    pub uncompressed_size: u64,
    /// Name of the file
    pub file_name: String,
    /// Raw file name. To be used when file_name was incorrectly decoded.
    pub file_name_raw: Vec<u8>,
    /// File comment
    pub file_comment: String,
    /// Specifies where the local header of the file starts
    pub header_start: u64,
    /// Specifies where the compressed data of the file starts
    pub data_start: u64,
    /// External file attributes
    pub external_attributes: u32,
}

impl ZipFileData {
    pub fn file_name_sanitized(&self) -> ::std::path::PathBuf {
        let no_null_filename: String = match self.file_name.find('\0') {
            Some(index) => &self.file_name[0..index],
            None => &self.file_name,
        }.to_string();

        // zip files can contain both / and \ as separators regardless of the OS
        // and as we want to return a sanitized PathBuf that only supports the
        // OS separator let's convert incompatible separators to compatible ones
        let separator = ::std::path::MAIN_SEPARATOR;
        let opposite_separator = match separator {
            '/' => '\\',
            '\\' | _ => '/',
        };
        let filename =
            no_null_filename.replace(&opposite_separator.to_string(), &separator.to_string());

        ::std::path::Path::new(&filename)
            .components()
            .filter(|component| match *component {
                ::std::path::Component::Normal(..) => true,
                _ => false,
            })
            .fold(::std::path::PathBuf::new(), |mut path, ref cur| {
                path.push(cur.as_os_str());
                path
            })
    }

    pub fn version_needed(&self) -> u16 {
        match self.compression_method {
            #[cfg(feature = "bzip2")]
            ::compression::CompressionMethod::Bzip2 => 46,
            _ => 20,
        }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn system() {
        use super::System;
        assert_eq!(System::Dos as u16, 0u16);
        assert_eq!(System::Unix as u16, 3u16);
        assert_eq!(System::from_u8(0), System::Dos);
        assert_eq!(System::from_u8(3), System::Unix);
    }

    #[test]
    fn sanitize() {
        use super::*;
        let file_name = "/path/../../../../etc/./passwd\0/etc/shadow".to_string();
        let data = ZipFileData {
            system: System::Dos,
            version_made_by: 0,
            encrypted: false,
            compression_method: ::compression::CompressionMethod::Stored,
            last_modified_time: time::empty_tm(),
            crc32: 0,
            compressed_size: 0,
            uncompressed_size: 0,
            file_name: file_name.clone(),
            file_name_raw: file_name.into_bytes(),
            file_comment: String::new(),
            header_start: 0,
            data_start: 0,
            external_attributes: 0,
        };
        assert_eq!(data.file_name_sanitized(), ::std::path::PathBuf::from("path/etc/passwd"));
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{CString, OsString};
use std::os::unix::ffi::OsStringExt;
use std::ptr;

use libc;

fn osstring2cstring(s: &OsString) -> CString {
    unsafe { CString::from_vec_unchecked(s.clone().into_vec()) }
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<&OsString>) {
    let mut args = Vec::new();
    for arg in &argv {
        args.push(osstring2cstring(arg).as_ptr());
    }
    args.push(ptr::null());
    assert!(unsafe { libc::execvp(args[0], args.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<OsString> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate.into_os_string());
            }
        }
    }
    None
}

pub fn find_pager(env: &str) -> Option<OsString> {
    let default_pager = || which("more");
    env::var_os(env).or_else(default_pager)
}

#[cfg(test)]
mod tests {
    use super::{find_pager, which};
    use std::ffi::OsString;

    #[cfg(target_os = "linux")]
    const MORE: &'static str = "/bin/more";

    #[cfg(target_os = "macos")]
    const MORE: &'static str = "/usr/bin/more";

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(OsString::from(MORE)));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        assert_eq!(find_pager("__RANDOM_NAME"), Some(OsString::from(MORE)));
    }
}
<commit_msg>Add support for NOPAGER<commit_after>use std::env;
use std::ffi::{CString, OsString};
use std::os::unix::ffi::OsStringExt;
use std::ptr;

use libc;

fn osstring2cstring(s: &OsString) -> CString {
    unsafe { CString::from_vec_unchecked(s.clone().into_vec()) }
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<&OsString>) {
    let mut args = Vec::new();
    for arg in &argv {
        args.push(osstring2cstring(arg).as_ptr());
    }
    args.push(ptr::null());
    assert!(unsafe { libc::execvp(args[0], args.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<OsString> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate.into_os_string());
            }
        }
    }
    None
}

pub fn find_pager(env: &str) -> Option<OsString> {
    if env::var_os("NOPAGER").is_some() {
        return None
    }
    let default_pager = || which("more");
    env::var_os(env).or_else(default_pager)
}

#[cfg(test)]
mod tests {
    use super::{find_pager, which};
    use std::ffi::OsString;

    #[cfg(target_os = "linux")]
    const MORE: &'static str = "/bin/more";

    #[cfg(target_os = "macos")]
    const MORE: &'static str = "/usr/bin/more";

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(OsString::from(MORE)));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        assert_eq!(find_pager("__RANDOM_NAME"), Some(OsString::from(MORE)));
    }
}
<|endoftext|>


<commit_before>//! Utility functions for use within wlroots-rs

use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::process::exit;
use std::time::Duration;

use libc::{clock_gettime, CLOCK_MONOTONIC, timespec};

use wlroots_sys::{__va_list_tag, log_importance_t, wlr_log_init};
pub use wlroots_sys::log_importance_t::*;

static mut RUST_LOGGING_FN: LogCallback = dummy_callback;

/// The signature for the callback function you can hook into the logging
/// functionality of wlroots.
pub type LogCallback = fn(LogVerbosity, String);

/// How verbose you want the logging. Lower levels prints more.
pub type LogVerbosity = log_importance_t;

/// Initialize wlroots logging at a certain level of verbosity with
/// an optional callback that will be called for every log.
///
/// To log using this system, use the `wlr_log!` macro.
// TODO Wrap the callback function type
pub fn init_logging<T>(verbosity: LogVerbosity, callback: T)
    where T: Into<Option<LogCallback>>
{
    unsafe {
        match callback.into() {
            None => wlr_log_init(verbosity, None),
            Some(callback) => {
                RUST_LOGGING_FN = callback;
                wlr_log_init(verbosity, Some(log_callback));
            }
        }
    }
}

/// Dummy callback to fill in RUST_LOGGING_FN when it's not in use.
fn dummy_callback(_: LogVerbosity, _: String) {}

/// Real hook into the logging callback, calls the real user-supplied callback
/// with nice Rust inputs.
unsafe extern "C" fn log_callback(importance: log_importance_t,
                                  fmt: *const c_char,
                                  _va_list: *mut __va_list_tag) {
    RUST_LOGGING_FN(importance,
                    c_to_rust_string(fmt).unwrap_or_else(|| "".into()))
}

/// Trait to convert something to mili seconds.
///
/// Used primarily to convert a `std::time::Duration` into
/// something usable by wlroots
pub trait ToMS {
    fn to_ms(self) -> u32;
}

impl ToMS for Duration {
    fn to_ms(self) -> u32 {
        let seconds_delta = self.as_secs() as u32;
        let nano_delta = self.subsec_nanos();
        (seconds_delta * 1000) + nano_delta / 1000000
    }
}

/// Converts a Rust string into C string without error handling.
/// If any error occurs, it is logged and then the program is immediantly
/// aborted.
pub fn safe_as_cstring<S>(string: S) -> CString
    where S: Into<Vec<u8>>
{
    match CString::new(string) {
        Ok(string) => string,
        Err(err) => {
            wlr_log!(L_ERROR,
                     "Error occured while trying to convert a Rust string to a C string {:?}",
                     err);
            exit(1)
        }
    }
}

/// Converts a C string into a Rust string without error handling.
/// The pointer passed to this function _must_ be valid.
pub unsafe fn c_to_rust_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        Some(CStr::from_ptr(c_str).to_string_lossy().into_owned())
    }
}

/// Handle unwinding from a panic, used in conjunction with
/// `::std::panic::catch_unwind`.
///
/// When a panic occurs, we terminate the compositor and let the rest
/// of the code run.
pub(crate) unsafe fn handle_unwind<T>(res: ::std::thread::Result<T>) {
    match res {
        Ok(_) => {}
        Err(err) => {
            if ::compositor::COMPOSITOR_PTR == 0 as *mut _ {
                ::std::process::abort();
            }
            (&mut *::compositor::COMPOSITOR_PTR).save_panic_error(err);
            ::compositor::terminate()
        }
    }
}

/// Get the current time as a duration suitable for `surface.send_frame_done()` and synthetic seat
/// events.
pub fn current_time() -> Duration {
    unsafe {
        let mut ts = timespec{tv_sec: 0, tv_nsec: 0};
        clock_gettime(CLOCK_MONOTONIC, &mut ts);
        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
    }
}

extern crate bitflags;
use wlroots_sys::{wlr_edges};

bitflags! {
    pub struct Edges: u32 {
        const WLR_EDGE_NONE = wlr_edges::WLR_EDGE_NONE as u32;
        const WLR_EDGE_TOP = wlr_edges::WLR_EDGE_TOP as u32;
        const WLR_EDGE_BOTTOM = wlr_edges::WLR_EDGE_BOTTOM as u32;
        const WLR_EDGE_LEFT = wlr_edges::WLR_EDGE_LEFT as u32;
        const WLR_EDGE_RIGHT = wlr_edges::WLR_EDGE_RIGHT as u32;
    }
}
<commit_msg>Fixed extern/import in utils<commit_after>//! Utility functions for use within wlroots-rs

use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::process::exit;
use std::time::Duration;

use libc::{clock_gettime, CLOCK_MONOTONIC, timespec};

use wlroots_sys::{__va_list_tag, log_importance_t, wlr_log_init, wlr_edges};
pub use wlroots_sys::log_importance_t::*;

static mut RUST_LOGGING_FN: LogCallback = dummy_callback;

/// The signature for the callback function you can hook into the logging
/// functionality of wlroots.
pub type LogCallback = fn(LogVerbosity, String);

/// How verbose you want the logging. Lower levels prints more.
pub type LogVerbosity = log_importance_t;

/// Initialize wlroots logging at a certain level of verbosity with
/// an optional callback that will be called for every log.
///
/// To log using this system, use the `wlr_log!` macro.
// TODO Wrap the callback function type
pub fn init_logging<T>(verbosity: LogVerbosity, callback: T)
    where T: Into<Option<LogCallback>>
{
    unsafe {
        match callback.into() {
            None => wlr_log_init(verbosity, None),
            Some(callback) => {
                RUST_LOGGING_FN = callback;
                wlr_log_init(verbosity, Some(log_callback));
            }
        }
    }
}

/// Dummy callback to fill in RUST_LOGGING_FN when it's not in use.
fn dummy_callback(_: LogVerbosity, _: String) {}

/// Real hook into the logging callback, calls the real user-supplied callback
/// with nice Rust inputs.
unsafe extern "C" fn log_callback(importance: log_importance_t,
                                  fmt: *const c_char,
                                  _va_list: *mut __va_list_tag) {
    RUST_LOGGING_FN(importance,
                    c_to_rust_string(fmt).unwrap_or_else(|| "".into()))
}

/// Trait to convert something to mili seconds.
///
/// Used primarily to convert a `std::time::Duration` into
/// something usable by wlroots
pub trait ToMS {
    fn to_ms(self) -> u32;
}

impl ToMS for Duration {
    fn to_ms(self) -> u32 {
        let seconds_delta = self.as_secs() as u32;
        let nano_delta = self.subsec_nanos();
        (seconds_delta * 1000) + nano_delta / 1000000
    }
}

/// Converts a Rust string into C string without error handling.
/// If any error occurs, it is logged and then the program is immediantly
/// aborted.
pub fn safe_as_cstring<S>(string: S) -> CString
    where S: Into<Vec<u8>>
{
    match CString::new(string) {
        Ok(string) => string,
        Err(err) => {
            wlr_log!(L_ERROR,
                     "Error occured while trying to convert a Rust string to a C string {:?}",
                     err);
            exit(1)
        }
    }
}

/// Converts a C string into a Rust string without error handling.
/// The pointer passed to this function _must_ be valid.
pub unsafe fn c_to_rust_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        Some(CStr::from_ptr(c_str).to_string_lossy().into_owned())
    }
}

/// Handle unwinding from a panic, used in conjunction with
/// `::std::panic::catch_unwind`.
///
/// When a panic occurs, we terminate the compositor and let the rest
/// of the code run.
pub(crate) unsafe fn handle_unwind<T>(res: ::std::thread::Result<T>) {
    match res {
        Ok(_) => {}
        Err(err) => {
            if ::compositor::COMPOSITOR_PTR == 0 as *mut _ {
                ::std::process::abort();
            }
            (&mut *::compositor::COMPOSITOR_PTR).save_panic_error(err);
            ::compositor::terminate()
        }
    }
}

/// Get the current time as a duration suitable for `surface.send_frame_done()` and synthetic seat
/// events.
pub fn current_time() -> Duration {
    unsafe {
        let mut ts = timespec{tv_sec: 0, tv_nsec: 0};
        clock_gettime(CLOCK_MONOTONIC, &mut ts);
        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
    }
}

bitflags! {
    pub struct Edges: u32 {
        const WLR_EDGE_NONE = wlr_edges::WLR_EDGE_NONE as u32;
        const WLR_EDGE_TOP = wlr_edges::WLR_EDGE_TOP as u32;
        const WLR_EDGE_BOTTOM = wlr_edges::WLR_EDGE_BOTTOM as u32;
        const WLR_EDGE_LEFT = wlr_edges::WLR_EDGE_LEFT as u32;
        const WLR_EDGE_RIGHT = wlr_edges::WLR_EDGE_RIGHT as u32;
    }
}
<|endoftext|>


<commit_before>// Adapted from libsyntax.

//! AST walker. Each overridden visit method has full control over what
//! happens with its node, it can do its own traversal of the node's children,
//! call `visit::walk_*` to apply the default traversal algorithm, or prevent
//! deeper traversal by doing nothing.
//!
//! Note: it is an important invariant that the default visitor walks the body
//! of a function in "execution order" (more concretely, reverse post-order
//! with respect to the CFG implied by the AST), meaning that if AST node A may
//! execute before AST node B, then A is visited first.  The borrow checker in
//! particular relies on this property.
//!
//! Note: walking an AST before macro expansion is probably a bad idea. For
//! instance, a walker looking for item names in a module will miss all of
//! those that are created by the expansion of a macro.

use super::*;

/// Each method of the Visitor trait is a hook to be potentially
/// overridden.  Each method's default implementation recursively visits
/// the substructure of the input via the corresponding `walk` method;
/// e.g. the `visit_mod` method by default calls `visit::walk_mod`.
///
/// If you want to ensure that your code handles every variant
/// explicitly, you need to override each method.  (And you also need
/// to monitor future changes to `Visitor` in case a new method with a
/// new default implementation gets introduced.)
pub trait Visitor: Sized {
    fn visit_ident(&mut self, _ident: &Ident) {}
    fn visit_macro_input(&mut self, macro_input: &MacroInput) {
        walk_macro_input(self, macro_input)
    }
    fn visit_ty(&mut self, ty: &Ty) {
        walk_ty(self, ty)
    }
    fn visit_generics(&mut self, generics: &Generics) {
        walk_generics(self, generics)
    }
    fn visit_ty_param_bound(&mut self, bound: &TyParamBound) {
        walk_ty_param_bound(self, bound)
    }
    fn visit_poly_trait_ref(&mut self, trait_ref: &PolyTraitRef, modifier: &TraitBoundModifier) {
        walk_poly_trait_ref(self, trait_ref, modifier)
    }
    fn visit_variant_data(&mut self, data: &VariantData, _ident: &Ident, _generics: &Generics) {
        walk_variant_data(self, data)
    }
    fn visit_field(&mut self, field: &Field) {
        walk_field(self, field)
    }
    fn visit_variant(&mut self, variant: &Variant, generics: &Generics) {
        walk_variant(self, variant, generics)
    }
    fn visit_lifetime(&mut self, _lifetime: &Lifetime) {}
    fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) {
        walk_lifetime_def(self, lifetime)
    }
    fn visit_path(&mut self, path: &Path) {
        walk_path(self, path)
    }
    fn visit_path_segment(&mut self, path_segment: &PathSegment) {
        walk_path_segment(self, path_segment)
    }
    fn visit_path_parameters(&mut self, path_parameters: &PathParameters) {
        walk_path_parameters(self, path_parameters)
    }
    fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
        walk_assoc_type_binding(self, type_binding)
    }
    fn visit_attribute(&mut self, _attr: &Attribute) {}
    fn visit_fn_ret_ty(&mut self, ret_ty: &FunctionRetTy) {
        walk_fn_ret_ty(self, ret_ty)
    }
    fn visit_const_expr(&mut self, expr: &ConstExpr) {
        walk_const_expr(self, expr)
    }
    fn visit_lit(&mut self, _lit: &Lit) {}
}

#[macro_export]
macro_rules! walk_list {
    ($visitor: expr, $method: ident, $list: expr) => {
        for elem in $list {
            $visitor.$method(elem)
        }
    };
    ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
        for elem in $list {
            $visitor.$method(elem, $($extra_args,)*)
        }
    }
}

pub fn walk_opt_ident<V: Visitor>(visitor: &mut V, opt_ident: &Option<Ident>) {
    if let Some(ref ident) = *opt_ident {
        visitor.visit_ident(ident);
    }
}

pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
    visitor.visit_lifetime(&lifetime_def.lifetime);
    walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
}

pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
    where V: Visitor
{
    walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
    visitor.visit_path(&trait_ref.trait_ref);
}

pub fn walk_macro_input<V: Visitor>(visitor: &mut V, macro_input: &MacroInput) {
    visitor.visit_ident(&macro_input.ident);
    visitor.visit_generics(&macro_input.generics);
    match macro_input.body {
        Body::Enum(ref variants) => {
            walk_list!(visitor, visit_variant, variants, &macro_input.generics);
        }
        Body::Struct(ref variant_data) => {
            visitor.visit_variant_data(variant_data, &macro_input.ident, &macro_input.generics);
        }
    }
    walk_list!(visitor, visit_attribute, &macro_input.attrs);
}

pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics)
    where V: Visitor
{
    visitor.visit_ident(&variant.ident);
    visitor.visit_variant_data(&variant.data, &variant.ident, generics);
    walk_list!(visitor, visit_attribute, &variant.attrs);
}

pub fn walk_ty<V: Visitor>(visitor: &mut V, ty: &Ty) {
    match *ty {
        Ty::Slice(ref inner) |
        Ty::Paren(ref inner) => visitor.visit_ty(inner),
        Ty::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
        Ty::Rptr(ref opt_lifetime, ref mutable_type) => {
            walk_list!(visitor, visit_lifetime, opt_lifetime);
            visitor.visit_ty(&mutable_type.ty)
        }
        Ty::Never | Ty::Infer => {}
        Ty::Tup(ref tuple_element_types) => {
            walk_list!(visitor, visit_ty, tuple_element_types);
        }
        Ty::BareFn(ref bare_fn) => {
            walk_list!(visitor, visit_lifetime_def, &bare_fn.lifetimes);
            for argument in &bare_fn.inputs {
                walk_opt_ident(visitor, &argument.name);
                visitor.visit_ty(&argument.ty)
            }
            visitor.visit_fn_ret_ty(&bare_fn.output)
        }
        Ty::Path(ref maybe_qself, ref path) => {
            if let Some(ref qself) = *maybe_qself {
                visitor.visit_ty(&qself.ty);
            }
            visitor.visit_path(path);
        }
        Ty::ObjectSum(ref inner, ref bounds) => {
            visitor.visit_ty(inner);
            walk_list!(visitor, visit_ty_param_bound, bounds);
        }
        Ty::Array(ref inner, ref len) => {
            visitor.visit_ty(inner);
            visitor.visit_const_expr(len);
        }
        Ty::PolyTraitRef(ref bounds) |
        Ty::ImplTrait(ref bounds) => {
            walk_list!(visitor, visit_ty_param_bound, bounds);
        }
    }
}

pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) {
    for segment in &path.segments {
        visitor.visit_path_segment(segment);
    }
}

pub fn walk_path_segment<V: Visitor>(visitor: &mut V, segment: &PathSegment) {
    visitor.visit_ident(&segment.ident);
    visitor.visit_path_parameters(&segment.parameters);
}

pub fn walk_path_parameters<V>(visitor: &mut V, path_parameters: &PathParameters)
    where V: Visitor
{
    match *path_parameters {
        PathParameters::AngleBracketed(ref data) => {
            walk_list!(visitor, visit_ty, &data.types);
            walk_list!(visitor, visit_lifetime, &data.lifetimes);
            walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
        }
        PathParameters::Parenthesized(ref data) => {
            walk_list!(visitor, visit_ty, &data.inputs);
            walk_list!(visitor, visit_ty, &data.output);
        }
    }
}

pub fn walk_assoc_type_binding<V: Visitor>(visitor: &mut V, type_binding: &TypeBinding) {
    visitor.visit_ident(&type_binding.ident);
    visitor.visit_ty(&type_binding.ty);
}

pub fn walk_ty_param_bound<V: Visitor>(visitor: &mut V, bound: &TyParamBound) {
    match *bound {
        TyParamBound::Trait(ref ty, ref modifier) => {
            visitor.visit_poly_trait_ref(ty, modifier);
        }
        TyParamBound::Region(ref lifetime) => {
            visitor.visit_lifetime(lifetime);
        }
    }
}

pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
    for param in &generics.ty_params {
        visitor.visit_ident(&param.ident);
        walk_list!(visitor, visit_ty_param_bound, &param.bounds);
        walk_list!(visitor, visit_ty, &param.default);
    }
    walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
    for predicate in &generics.where_clause.predicates {
        match *predicate {
            WherePredicate::BoundPredicate(WhereBoundPredicate { ref bounded_ty,
                                                                 ref bounds,
                                                                 ref bound_lifetimes,
                                                                 .. }) => {
                visitor.visit_ty(bounded_ty);
                walk_list!(visitor, visit_ty_param_bound, bounds);
                walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
            }
            WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime,
                                                                   ref bounds,
                                                                   .. }) => {
                visitor.visit_lifetime(lifetime);
                walk_list!(visitor, visit_lifetime, bounds);
            }
        }
    }
}

pub fn walk_fn_ret_ty<V: Visitor>(visitor: &mut V, ret_ty: &FunctionRetTy) {
    if let FunctionRetTy::Ty(ref output_ty) = *ret_ty {
        visitor.visit_ty(output_ty)
    }
}

pub fn walk_variant_data<V: Visitor>(visitor: &mut V, data: &VariantData) {
    walk_list!(visitor, visit_field, data.fields());
}

pub fn walk_field<V: Visitor>(visitor: &mut V, field: &Field) {
    walk_opt_ident(visitor, &field.ident);
    visitor.visit_ty(&field.ty);
    walk_list!(visitor, visit_attribute, &field.attrs);
}

pub fn walk_const_expr<V: Visitor>(visitor: &mut V, len: &ConstExpr) {
    match *len {
        ConstExpr::Call(ref function, ref args) => {
            visitor.visit_const_expr(function);
            walk_list!(visitor, visit_const_expr, args);
        }
        ConstExpr::Binary(_op, ref left, ref right) => {
            visitor.visit_const_expr(left);
            visitor.visit_const_expr(right);
        }
        ConstExpr::Unary(_op, ref v) => {
            visitor.visit_const_expr(v);
        }
        ConstExpr::Lit(ref lit) => {
            visitor.visit_lit(lit);
        }
        ConstExpr::Cast(ref expr, ref ty) => {
            visitor.visit_const_expr(expr);
            visitor.visit_ty(ty);
        }
        ConstExpr::Path(ref path) => {
            visitor.visit_path(path);
        }
    }
}
<commit_msg>Update visitor with parenthesized const expressions<commit_after>// Adapted from libsyntax.

//! AST walker. Each overridden visit method has full control over what
//! happens with its node, it can do its own traversal of the node's children,
//! call `visit::walk_*` to apply the default traversal algorithm, or prevent
//! deeper traversal by doing nothing.
//!
//! Note: it is an important invariant that the default visitor walks the body
//! of a function in "execution order" (more concretely, reverse post-order
//! with respect to the CFG implied by the AST), meaning that if AST node A may
//! execute before AST node B, then A is visited first.  The borrow checker in
//! particular relies on this property.
//!
//! Note: walking an AST before macro expansion is probably a bad idea. For
//! instance, a walker looking for item names in a module will miss all of
//! those that are created by the expansion of a macro.

use super::*;

/// Each method of the Visitor trait is a hook to be potentially
/// overridden.  Each method's default implementation recursively visits
/// the substructure of the input via the corresponding `walk` method;
/// e.g. the `visit_mod` method by default calls `visit::walk_mod`.
///
/// If you want to ensure that your code handles every variant
/// explicitly, you need to override each method.  (And you also need
/// to monitor future changes to `Visitor` in case a new method with a
/// new default implementation gets introduced.)
pub trait Visitor: Sized {
    fn visit_ident(&mut self, _ident: &Ident) {}
    fn visit_macro_input(&mut self, macro_input: &MacroInput) {
        walk_macro_input(self, macro_input)
    }
    fn visit_ty(&mut self, ty: &Ty) {
        walk_ty(self, ty)
    }
    fn visit_generics(&mut self, generics: &Generics) {
        walk_generics(self, generics)
    }
    fn visit_ty_param_bound(&mut self, bound: &TyParamBound) {
        walk_ty_param_bound(self, bound)
    }
    fn visit_poly_trait_ref(&mut self, trait_ref: &PolyTraitRef, modifier: &TraitBoundModifier) {
        walk_poly_trait_ref(self, trait_ref, modifier)
    }
    fn visit_variant_data(&mut self, data: &VariantData, _ident: &Ident, _generics: &Generics) {
        walk_variant_data(self, data)
    }
    fn visit_field(&mut self, field: &Field) {
        walk_field(self, field)
    }
    fn visit_variant(&mut self, variant: &Variant, generics: &Generics) {
        walk_variant(self, variant, generics)
    }
    fn visit_lifetime(&mut self, _lifetime: &Lifetime) {}
    fn visit_lifetime_def(&mut self, lifetime: &LifetimeDef) {
        walk_lifetime_def(self, lifetime)
    }
    fn visit_path(&mut self, path: &Path) {
        walk_path(self, path)
    }
    fn visit_path_segment(&mut self, path_segment: &PathSegment) {
        walk_path_segment(self, path_segment)
    }
    fn visit_path_parameters(&mut self, path_parameters: &PathParameters) {
        walk_path_parameters(self, path_parameters)
    }
    fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) {
        walk_assoc_type_binding(self, type_binding)
    }
    fn visit_attribute(&mut self, _attr: &Attribute) {}
    fn visit_fn_ret_ty(&mut self, ret_ty: &FunctionRetTy) {
        walk_fn_ret_ty(self, ret_ty)
    }
    fn visit_const_expr(&mut self, expr: &ConstExpr) {
        walk_const_expr(self, expr)
    }
    fn visit_lit(&mut self, _lit: &Lit) {}
}

#[macro_export]
macro_rules! walk_list {
    ($visitor: expr, $method: ident, $list: expr) => {
        for elem in $list {
            $visitor.$method(elem)
        }
    };
    ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
        for elem in $list {
            $visitor.$method(elem, $($extra_args,)*)
        }
    }
}

pub fn walk_opt_ident<V: Visitor>(visitor: &mut V, opt_ident: &Option<Ident>) {
    if let Some(ref ident) = *opt_ident {
        visitor.visit_ident(ident);
    }
}

pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
    visitor.visit_lifetime(&lifetime_def.lifetime);
    walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
}

pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
    where V: Visitor
{
    walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
    visitor.visit_path(&trait_ref.trait_ref);
}

pub fn walk_macro_input<V: Visitor>(visitor: &mut V, macro_input: &MacroInput) {
    visitor.visit_ident(&macro_input.ident);
    visitor.visit_generics(&macro_input.generics);
    match macro_input.body {
        Body::Enum(ref variants) => {
            walk_list!(visitor, visit_variant, variants, &macro_input.generics);
        }
        Body::Struct(ref variant_data) => {
            visitor.visit_variant_data(variant_data, &macro_input.ident, &macro_input.generics);
        }
    }
    walk_list!(visitor, visit_attribute, &macro_input.attrs);
}

pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics)
    where V: Visitor
{
    visitor.visit_ident(&variant.ident);
    visitor.visit_variant_data(&variant.data, &variant.ident, generics);
    walk_list!(visitor, visit_attribute, &variant.attrs);
}

pub fn walk_ty<V: Visitor>(visitor: &mut V, ty: &Ty) {
    match *ty {
        Ty::Slice(ref inner) |
        Ty::Paren(ref inner) => visitor.visit_ty(inner),
        Ty::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
        Ty::Rptr(ref opt_lifetime, ref mutable_type) => {
            walk_list!(visitor, visit_lifetime, opt_lifetime);
            visitor.visit_ty(&mutable_type.ty)
        }
        Ty::Never | Ty::Infer => {}
        Ty::Tup(ref tuple_element_types) => {
            walk_list!(visitor, visit_ty, tuple_element_types);
        }
        Ty::BareFn(ref bare_fn) => {
            walk_list!(visitor, visit_lifetime_def, &bare_fn.lifetimes);
            for argument in &bare_fn.inputs {
                walk_opt_ident(visitor, &argument.name);
                visitor.visit_ty(&argument.ty)
            }
            visitor.visit_fn_ret_ty(&bare_fn.output)
        }
        Ty::Path(ref maybe_qself, ref path) => {
            if let Some(ref qself) = *maybe_qself {
                visitor.visit_ty(&qself.ty);
            }
            visitor.visit_path(path);
        }
        Ty::ObjectSum(ref inner, ref bounds) => {
            visitor.visit_ty(inner);
            walk_list!(visitor, visit_ty_param_bound, bounds);
        }
        Ty::Array(ref inner, ref len) => {
            visitor.visit_ty(inner);
            visitor.visit_const_expr(len);
        }
        Ty::PolyTraitRef(ref bounds) |
        Ty::ImplTrait(ref bounds) => {
            walk_list!(visitor, visit_ty_param_bound, bounds);
        }
    }
}

pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) {
    for segment in &path.segments {
        visitor.visit_path_segment(segment);
    }
}

pub fn walk_path_segment<V: Visitor>(visitor: &mut V, segment: &PathSegment) {
    visitor.visit_ident(&segment.ident);
    visitor.visit_path_parameters(&segment.parameters);
}

pub fn walk_path_parameters<V>(visitor: &mut V, path_parameters: &PathParameters)
    where V: Visitor
{
    match *path_parameters {
        PathParameters::AngleBracketed(ref data) => {
            walk_list!(visitor, visit_ty, &data.types);
            walk_list!(visitor, visit_lifetime, &data.lifetimes);
            walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
        }
        PathParameters::Parenthesized(ref data) => {
            walk_list!(visitor, visit_ty, &data.inputs);
            walk_list!(visitor, visit_ty, &data.output);
        }
    }
}

pub fn walk_assoc_type_binding<V: Visitor>(visitor: &mut V, type_binding: &TypeBinding) {
    visitor.visit_ident(&type_binding.ident);
    visitor.visit_ty(&type_binding.ty);
}

pub fn walk_ty_param_bound<V: Visitor>(visitor: &mut V, bound: &TyParamBound) {
    match *bound {
        TyParamBound::Trait(ref ty, ref modifier) => {
            visitor.visit_poly_trait_ref(ty, modifier);
        }
        TyParamBound::Region(ref lifetime) => {
            visitor.visit_lifetime(lifetime);
        }
    }
}

pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
    for param in &generics.ty_params {
        visitor.visit_ident(&param.ident);
        walk_list!(visitor, visit_ty_param_bound, &param.bounds);
        walk_list!(visitor, visit_ty, &param.default);
    }
    walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
    for predicate in &generics.where_clause.predicates {
        match *predicate {
            WherePredicate::BoundPredicate(WhereBoundPredicate { ref bounded_ty,
                                                                 ref bounds,
                                                                 ref bound_lifetimes,
                                                                 .. }) => {
                visitor.visit_ty(bounded_ty);
                walk_list!(visitor, visit_ty_param_bound, bounds);
                walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
            }
            WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime,
                                                                   ref bounds,
                                                                   .. }) => {
                visitor.visit_lifetime(lifetime);
                walk_list!(visitor, visit_lifetime, bounds);
            }
        }
    }
}

pub fn walk_fn_ret_ty<V: Visitor>(visitor: &mut V, ret_ty: &FunctionRetTy) {
    if let FunctionRetTy::Ty(ref output_ty) = *ret_ty {
        visitor.visit_ty(output_ty)
    }
}

pub fn walk_variant_data<V: Visitor>(visitor: &mut V, data: &VariantData) {
    walk_list!(visitor, visit_field, data.fields());
}

pub fn walk_field<V: Visitor>(visitor: &mut V, field: &Field) {
    walk_opt_ident(visitor, &field.ident);
    visitor.visit_ty(&field.ty);
    walk_list!(visitor, visit_attribute, &field.attrs);
}

pub fn walk_const_expr<V: Visitor>(visitor: &mut V, len: &ConstExpr) {
    match *len {
        ConstExpr::Call(ref function, ref args) => {
            visitor.visit_const_expr(function);
            walk_list!(visitor, visit_const_expr, args);
        }
        ConstExpr::Binary(_op, ref left, ref right) => {
            visitor.visit_const_expr(left);
            visitor.visit_const_expr(right);
        }
        ConstExpr::Unary(_op, ref v) => {
            visitor.visit_const_expr(v);
        }
        ConstExpr::Lit(ref lit) => {
            visitor.visit_lit(lit);
        }
        ConstExpr::Cast(ref expr, ref ty) => {
            visitor.visit_const_expr(expr);
            visitor.visit_ty(ty);
        }
        ConstExpr::Path(ref path) => {
            visitor.visit_path(path);
        }
        ConstExpr::Paren(ref expr) => {
            visitor.visit_const_expr(expr);
        }
    }
}
<|endoftext|>


<commit_before>// The dictionary used for the lessons.

use rand::{Rng, thread_rng};
use serde_json;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fs::{File, rename};
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
use stroke::{self, Stroke};
use ::Result;

/// The set of words we are working on.  This represents the current state.
#[derive(Debug, Deserialize, Serialize)]
pub struct Words {
    /// The unlearned words come directly from the json problem sets.
    pub unlearned: Vec<Lesson>,

    pub learning: Vec<LearnWord>,
}

impl Words {
    /// Construct a new word set from internal data.
    pub fn new() -> Words {
        Words {
            unlearned: get_lessons(),
            learning: vec![],
        }
    }

    /// Load a wordset from the given file.
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Words> {
        let fd = File::open(path.as_ref())?;
        let result = serde_json::from_reader(&fd)?;
        Ok(result)
    }

    /// Save the wordset to a given file.
    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        let path = path.as_ref();
        let tmp = path.with_extension("tmp");
        {
            let mut fd = File::create(&tmp)?;
            // serde_json::to_writer_pretty(&mut fd, self)?;
            serde_json::to_writer(&mut fd, self)?;
            // serde_yaml::to_writer(&mut fd, self)?;
            // rmp_serde::encode::write(&mut fd, self)?;
        }
        rename(tmp, path)?;
        Ok(())
    }

    /// Extract a new word to learn.  Returns None if there are no more words.
    pub fn get_unlearned(&mut self) -> Option<LearnWord> {
        let mut lesson = match self.unlearned.pop() {
            None => return None,
            Some (l) => l,
        };

        let (strokes, english) = lesson.words.pop().expect("Words in list");

        let result = LearnWord {
            strokes: strokes,
            english: english,
            next: now() + 5.0,
            interval: 5.0,
        };

        // If there are more words in this lesson, push the lesson back.
        if !lesson.words.is_empty() {
            self.unlearned.push(lesson);
        }

        Some(result)
    }

    /// Extract a word to be learned, if were ready for it.
    pub fn get_learned(&mut self) -> Option<LearnWord> {
        match self.learning.pop() {
            None => None,
            Some(w) => {
                if now() >= w.next {
                    Some(w)
                } else {
                    self.learning.push(w);
                    None
                }
            }
        }
    }

    /// Push a word back into the unlearned word list.
    pub fn push_word(&mut self, word: LearnWord) {
        self.learning.push(word);
        self.learning.sort_by(word_cmp);
    }

    /// Return a count of the number of words that are pending.
    pub fn get_counts(&self) -> Counts {
        let n = now();

        // Divide all of the upcoming entries into buckets.
        let mut counts = vec![0; COUNT_BUCKETS.len()];

        for word in &self.learning {
            let mut v = word.interval;
            for (num, b) in COUNT_BUCKETS.iter().enumerate() {
                if v < b.limit {
                    counts[num] += 1;
                    break;
                }
                v /= b.limit;
            }
        }

        let buckets = COUNT_BUCKETS.iter().zip(counts).map(|(aa, bb)| Bucket {
            name: aa.name,
            count: bb,
        }).collect();

        Counts {
            active: self.learning.iter().filter(|x| x.next < n).count(),
            later: self.learning.iter().filter(|x| x.next >= n).count(),
            unlearned: self.unlearned.iter().map(|x| x.words.len()).sum(),

            buckets: buckets,
        }
    }
}

pub struct Counts {
    pub active: usize,
    pub later: usize,
    pub unlearned: usize,

    // Buckets for later.  The sum of all of these should match the `later+active` value above.
    pub buckets: Vec<Bucket>,
}

pub struct Bucket {
    pub name: &'static str,
    pub count: usize,
}

struct BucketBin {
    name: &'static str,
    limit: f64,
}

static COUNT_BUCKETS: &'static [BucketBin] = &[
    BucketBin{ name: "sec", limit: 60.0 },
    BucketBin{ name: "min", limit: 60.0 },
    BucketBin{ name: "hr", limit: 24.0 },
    BucketBin{ name: "day", limit: 30.0 },
    BucketBin{ name: "mon", limit: 1.0e30 },
];

#[derive(Debug, Serialize, Deserialize)]
pub struct LearnWord {
    pub strokes: Vec<Stroke>,
    pub english: String,
    pub next: f64,
    pub interval: f64,
}

impl LearnWord {
    pub fn correct(&mut self) {
        self.adjust(2.2)
    }

    pub fn incorrect(&mut self) {
        self.adjust(0.25)
    }

    fn adjust(&mut self, factor: f64) {
        let mut rng = thread_rng();
        let n = now();
        // If we've gone past the deadline, add this time to the interval.
        let interval = if factor > 1.0 {
            if n > self.next {
                self.interval + (n - self.next)
            } else {
                self.interval
            }
        } else {
            self.interval
        };
        // Compute the interval, capping with a minimum of 5 seconds.
        self.interval = (interval * factor * rng.gen_range(0.75, 1.25)).max(5.0);
        self.next = now() + self.interval;
    }
}

// Comparison is reversed to make it easy to have the newest at the end.
fn word_cmp(a: &LearnWord, b: &LearnWord) -> Ordering {
    b.next.partial_cmp(&a.next).unwrap()
}

// Get the current time as ticks.
fn now() -> f64 {
    let stamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let sec = stamp.as_secs();
    let nsec = stamp.subsec_nanos();

    sec as f64 + (nsec as f64 / 1.0e9)
}

type Dict = BTreeMap<Vec<Stroke>, String>;

fn get_dict() -> Dict {
    let json = include_str!("dict-canonical.json");
    let main: BTreeMap<String, String> = serde_json::from_str(json).unwrap();
    let mut result = BTreeMap::new();
    for (k, v) in main {
        result.insert(Stroke::parse_strokes(&k).unwrap(), v);
    }
    result
}

#[derive(Debug, Deserialize, Serialize)]
pub struct LessonInfo {
    pub title: String,
    pub include: Stroke,
    pub require: Stroke,
    pub tags: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Lesson {
    pub info: LessonInfo,
    pub words: Vec<(Vec<Stroke>, String)>,
}

fn get_lessons() -> Vec<Lesson> {
    let json = include_str!("lessons.json");
    let mut dict: Vec<(Vec<Stroke>, String)> = get_dict().into_iter().collect();
    let infos: Vec<LessonInfo> = serde_json::from_str(json).unwrap();

    let mut result = vec![];
    // Work through the lessons in order, assigning the problems to the first lesson that makes
    // sense.
    for info in infos {
        let (mut with, without): (Vec<_>, Vec<_>) = dict.into_iter().partition(|item| {
            let value = item.0[0].0;
            (value & !info.include.0 == 0) && (value & info.require.0 != 0)
        });
        with.reverse();
        if !with.is_empty() {
            result.push(Lesson {
                info: info,
                words: with,
            });
        }
        dict = without;
    }

    // Put the remaining words in a separate lesson.  The website will never ask for these, but we
    // should still learn them.
    // The 'require' can't ever be correct here, but we'll include something so that the saved data
    // will parse.
    result.push(Lesson {
        info: LessonInfo {
            title: "Uncategorized".to_string(),
            include: Stroke(stroke::NUM - 1),
            require: Stroke(1),
            tags: "Rest".to_string(),
        },
        words: dict,
    });

    result.reverse();

    result
}

#[cfg(test)]
mod test {
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn load_words() {
        let words = Words::new();
        println!("{} lessons", words.unlearned.len());
        for les in &words.unlearned {
            println!("  lesson {} words: {}", les.words.len(), les.info.title);
        }

        let tmp = TempDir::new("words-test").expect("create temp dir");
        let json_path = tmp.path().join("sample.json");
        words.save(&json_path).unwrap();

        let w2 = Words::load(&json_path).unwrap();
        assert_eq!(words.unlearned.len(), w2.unlearned.len());
    }
}
<commit_msg>Remove use of actual interval<commit_after>// The dictionary used for the lessons.

use rand::{Rng, thread_rng};
use serde_json;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fs::{File, rename};
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
use stroke::{self, Stroke};
use ::Result;

/// The set of words we are working on.  This represents the current state.
#[derive(Debug, Deserialize, Serialize)]
pub struct Words {
    /// The unlearned words come directly from the json problem sets.
    pub unlearned: Vec<Lesson>,

    pub learning: Vec<LearnWord>,
}

impl Words {
    /// Construct a new word set from internal data.
    pub fn new() -> Words {
        Words {
            unlearned: get_lessons(),
            learning: vec![],
        }
    }

    /// Load a wordset from the given file.
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Words> {
        let fd = File::open(path.as_ref())?;
        let result = serde_json::from_reader(&fd)?;
        Ok(result)
    }

    /// Save the wordset to a given file.
    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        let path = path.as_ref();
        let tmp = path.with_extension("tmp");
        {
            let mut fd = File::create(&tmp)?;
            // serde_json::to_writer_pretty(&mut fd, self)?;
            serde_json::to_writer(&mut fd, self)?;
            // serde_yaml::to_writer(&mut fd, self)?;
            // rmp_serde::encode::write(&mut fd, self)?;
        }
        rename(tmp, path)?;
        Ok(())
    }

    /// Extract a new word to learn.  Returns None if there are no more words.
    pub fn get_unlearned(&mut self) -> Option<LearnWord> {
        let mut lesson = match self.unlearned.pop() {
            None => return None,
            Some (l) => l,
        };

        let (strokes, english) = lesson.words.pop().expect("Words in list");

        let result = LearnWord {
            strokes: strokes,
            english: english,
            next: now() + 5.0,
            interval: 5.0,
        };

        // If there are more words in this lesson, push the lesson back.
        if !lesson.words.is_empty() {
            self.unlearned.push(lesson);
        }

        Some(result)
    }

    /// Extract a word to be learned, if were ready for it.
    pub fn get_learned(&mut self) -> Option<LearnWord> {
        match self.learning.pop() {
            None => None,
            Some(w) => {
                if now() >= w.next {
                    Some(w)
                } else {
                    self.learning.push(w);
                    None
                }
            }
        }
    }

    /// Push a word back into the unlearned word list.
    pub fn push_word(&mut self, word: LearnWord) {
        self.learning.push(word);
        self.learning.sort_by(word_cmp);
    }

    /// Return a count of the number of words that are pending.
    pub fn get_counts(&self) -> Counts {
        let n = now();

        // Divide all of the upcoming entries into buckets.
        let mut counts = vec![0; COUNT_BUCKETS.len()];

        for word in &self.learning {
            let mut v = word.interval;
            for (num, b) in COUNT_BUCKETS.iter().enumerate() {
                if v < b.limit {
                    counts[num] += 1;
                    break;
                }
                v /= b.limit;
            }
        }

        let buckets = COUNT_BUCKETS.iter().zip(counts).map(|(aa, bb)| Bucket {
            name: aa.name,
            count: bb,
        }).collect();

        Counts {
            active: self.learning.iter().filter(|x| x.next < n).count(),
            later: self.learning.iter().filter(|x| x.next >= n).count(),
            unlearned: self.unlearned.iter().map(|x| x.words.len()).sum(),

            buckets: buckets,
        }
    }
}

pub struct Counts {
    pub active: usize,
    pub later: usize,
    pub unlearned: usize,

    // Buckets for later.  The sum of all of these should match the `later+active` value above.
    pub buckets: Vec<Bucket>,
}

pub struct Bucket {
    pub name: &'static str,
    pub count: usize,
}

struct BucketBin {
    name: &'static str,
    limit: f64,
}

static COUNT_BUCKETS: &'static [BucketBin] = &[
    BucketBin{ name: "sec", limit: 60.0 },
    BucketBin{ name: "min", limit: 60.0 },
    BucketBin{ name: "hr", limit: 24.0 },
    BucketBin{ name: "day", limit: 30.0 },
    BucketBin{ name: "mon", limit: 1.0e30 },
];

#[derive(Debug, Serialize, Deserialize)]
pub struct LearnWord {
    pub strokes: Vec<Stroke>,
    pub english: String,
    pub next: f64,
    pub interval: f64,
}

impl LearnWord {
    pub fn correct(&mut self) {
        self.adjust(2.2)
    }

    pub fn incorrect(&mut self) {
        self.adjust(0.25)
    }

    fn adjust(&mut self, factor: f64) {
        let mut rng = thread_rng();
        let interval = self.interval;
        // Compute the interval, capping with a minimum of 5 seconds.
        self.interval = (interval * factor * rng.gen_range(0.75, 1.25)).max(5.0);
        self.next = now() + self.interval;
    }
}

// Comparison is reversed to make it easy to have the newest at the end.
fn word_cmp(a: &LearnWord, b: &LearnWord) -> Ordering {
    b.next.partial_cmp(&a.next).unwrap()
}

// Get the current time as ticks.
fn now() -> f64 {
    let stamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let sec = stamp.as_secs();
    let nsec = stamp.subsec_nanos();

    sec as f64 + (nsec as f64 / 1.0e9)
}

type Dict = BTreeMap<Vec<Stroke>, String>;

fn get_dict() -> Dict {
    let json = include_str!("dict-canonical.json");
    let main: BTreeMap<String, String> = serde_json::from_str(json).unwrap();
    let mut result = BTreeMap::new();
    for (k, v) in main {
        result.insert(Stroke::parse_strokes(&k).unwrap(), v);
    }
    result
}

#[derive(Debug, Deserialize, Serialize)]
pub struct LessonInfo {
    pub title: String,
    pub include: Stroke,
    pub require: Stroke,
    pub tags: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Lesson {
    pub info: LessonInfo,
    pub words: Vec<(Vec<Stroke>, String)>,
}

fn get_lessons() -> Vec<Lesson> {
    let json = include_str!("lessons.json");
    let mut dict: Vec<(Vec<Stroke>, String)> = get_dict().into_iter().collect();
    let infos: Vec<LessonInfo> = serde_json::from_str(json).unwrap();

    let mut result = vec![];
    // Work through the lessons in order, assigning the problems to the first lesson that makes
    // sense.
    for info in infos {
        let (mut with, without): (Vec<_>, Vec<_>) = dict.into_iter().partition(|item| {
            let value = item.0[0].0;
            (value & !info.include.0 == 0) && (value & info.require.0 != 0)
        });
        with.reverse();
        if !with.is_empty() {
            result.push(Lesson {
                info: info,
                words: with,
            });
        }
        dict = without;
    }

    // Put the remaining words in a separate lesson.  The website will never ask for these, but we
    // should still learn them.
    // The 'require' can't ever be correct here, but we'll include something so that the saved data
    // will parse.
    result.push(Lesson {
        info: LessonInfo {
            title: "Uncategorized".to_string(),
            include: Stroke(stroke::NUM - 1),
            require: Stroke(1),
            tags: "Rest".to_string(),
        },
        words: dict,
    });

    result.reverse();

    result
}

#[cfg(test)]
mod test {
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn load_words() {
        let words = Words::new();
        println!("{} lessons", words.unlearned.len());
        for les in &words.unlearned {
            println!("  lesson {} words: {}", les.words.len(), les.info.title);
        }

        let tmp = TempDir::new("words-test").expect("create temp dir");
        let json_path = tmp.path().join("sample.json");
        words.save(&json_path).unwrap();

        let w2 = Words::load(&json_path).unwrap();
        assert_eq!(words.unlearned.len(), w2.unlearned.len());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly-testing", feature(plugin))]
#![cfg_attr(feature = "nightly-testing", plugin(clippy))]

#[macro_use]
extern crate clap;
extern crate rayon;
extern crate rustfmt;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;
extern crate inflector;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate hyper;

mod cargo;
mod codegen;
mod config;
mod service;

use std::fs::{self, OpenOptions};
use std::io::{Write, BufWriter};
use std::path::Path;

use rayon::prelude::*;

use clap::{Arg, App};

use codegen::botocore::{ServiceDefinition};
pub use service::Service;
use config::ServiceConfig;

fn main() {
    let matches = App::new("Rusoto Service Crate Generator")
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("services_config")
            .long("config")
            .short("c")
            .takes_value(true))
        .arg(Arg::with_name("out_dir")
            .long("outdir")
            .short("o")
            .takes_value(true)
            .required(true))
        .get_matches();

    let out_dir = Path::new(matches.value_of("out_dir").unwrap());

    if !out_dir.exists() {
        fs::create_dir(out_dir).expect("Unable to create output directory");
    }

    let services_config_path = matches.value_of("services_config").unwrap();
    let service_configs = ServiceConfig::load_all(services_config_path).expect("Unable to read services configuration file.");

    service_configs.par_iter().for_each(|&(ref name, ref service_config)| {
        let service = {
            let service_definition = ServiceDefinition::load(name, &service_config.protocol_version)
                .expect(&format!("Failed to load service {}. Make sure the botocore submodule has been initialized!", name));
            Service::new(service_config.clone(), service_definition)
        };

        let crate_dir = out_dir.join(&name);
        let crate_name = format!("rusoto_{}", &name.replace('-', "_"));

        println!("Generating crate for {} @ {}...", service.full_name(), service.api_version());

        if !crate_dir.exists() {
            fs::create_dir(&crate_dir).expect(&format!("Unable to create directory at {}", crate_dir.display()));
        }

        let service_dependencies = service.get_dependencies();

        let extern_crates = service_dependencies.iter().map(|(k, _)| {
            if k == "xml-rs" {
                return "extern crate xml;".into();
            }
            let safe_name = k.replace("-", "_");
            let use_macro = k == "serde_derive" || k == "log" || k == "lazy_static";
            if use_macro {
                return format!("#[macro_use]\nextern crate {};", safe_name);
            }
            format!("extern crate {};", safe_name)
        }).collect::<Vec<String>>().join("\n");

        let mut cargo_manifest = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(crate_dir.join("Cargo.toml"))
            .expect("Unable to write Cargo.toml");

        let manifest = cargo::Manifest {
            package: cargo::Metadata {
                authors: Some(vec![
                    "Anthony DiMarco <ocramida@gmail.com>".into(),
                    "Jimmy Cuadra <jimmy@jimmycuadra.com>".into(),
                    "Matthew Mayer <matthewkmayer@gmail.com>".into(),
                    "Nikita Pekin <contact@nikitapek.in>".into()
                ]),
                description: Some(format!("AWS SDK for Rust - {} @ {}", service.full_name(), service.api_version())),
                documentation: Some("https://rusoto.github.io/rusoto/rusoto_core/index.html".into()),
                keywords: Some(vec!["AWS".into(), "Amazon".into(), name.clone()]),
                license: Some("MIT".into()),
                name: crate_name.clone(),
                readme: Some("README.md".into()),
                repository: Some("https://github.com/rusoto/rusoto".into()),
                version: service_config.version.clone(),
                homepage: Some("https://www.rusoto.org/".into()),
                ..cargo::Metadata::default()
            },
            dependencies: service_dependencies,
            dev_dependencies: vec![
                ("rusoto_mock".to_owned(), cargo::Dependency::Extended {
                    path: Some("../../../mock".into()),
                    version: Some("0.24.0".into()),
                    optional: None,
                    default_features: None,
                    features: None
                })
            ].into_iter().collect(),
            ..cargo::Manifest::default()
        };

        cargo_manifest.write_all(toml::to_string(&manifest).unwrap().as_bytes()).unwrap();

        let mut readme_file = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(crate_dir.join("README.md"))
            .expect("Unable to write README.md");

        let readme = format!(r#"
# Rusoto {short_name}
Rust SDK for {aws_name}

You may be looking for:

* [An overview of Rusoto][rusoto-overview]
* [AWS services supported by Rusoto][supported-aws-services]
* [API documentation][api-documentation]
* [Getting help with Rusoto][rusoto-help]

## Requirements

Rust stable or beta are required to use Rusoto. Nightly is tested, but not guaranteed to be supported. Older
versions _may_ be supported. The currently supported Rust versions can be found in the Rusoto project
[`travis.yml`](https://github.com/rusoto/rusoto/blob/master/.travis.yml).

On Linux, OpenSSL is required.

## Installation

To use `{crate_name}` in your application, add it as a dependency in your `Cargo.toml`:

```toml
[dependencies]
{crate_name} = "{version}"
```

## Contributing

See [CONTRIBUTING][contributing].

## License

Rusoto is distributed under the terms of the MIT license.

See [LICENSE][license] for details.

[api-documentation]: https://rusoto.github.io/rusoto/rusoto/ "API documentation"
[license]: https://github.com/rusoto/rusoto/blob/master/LICENSE "MIT License"
[contributing]: https://github.com/rusoto/rusoto/blob/master/CONTRIBUTING.md "Contributing Guide"
[rusoto-help]: https://www.rusoto.org/help.html "Getting help with Rusoto"
[rusoto-overview]: https://www.rusoto.org/ "Rusoto overview"
[supported-aws-services]: https://www.rusoto.org/supported-aws-services.html "List of AWS services supported by Rusoto"
        "#,
        short_name = service.service_type_name(),
        aws_name = service.full_name(),
        crate_name = crate_name,
        version = service_config.version
        );

        readme_file.write_all(readme.as_bytes()).unwrap();

        {
            let src_dir = crate_dir.join("src");

            if !src_dir.exists() {
                fs::create_dir(&src_dir).expect(&format!("Unable to create directory at {}", src_dir.display()));
            }

            let lib_file_path = src_dir.join("lib.rs");

            let mut lib_file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(&lib_file_path)
                .expect("Unable to write lib.rs");

            let lib_file_contents = format!(r#"
//! {service_full_name}
//!
//! If you're using the service, you're probably looking for [{client_name}](struct.{client_name}.html) and [{trait_name}](trait.{trait_name}.html).

{extern_crates}

mod generated;
mod custom;

pub use generated::*;
pub use custom::*;
            "#,
            service_full_name = service.full_name(),
            client_name = service.client_type_name(),
            trait_name = service.service_type_name(),
            extern_crates = extern_crates
            );

            lib_file.write_all(lib_file_contents.as_bytes()).unwrap();

            let gen_file_path = src_dir.join("generated.rs");

            let gen_file = OpenOptions::new()
                .create(true)
                .write(true)
                .truncate(true)
                .open(&gen_file_path)
                .expect("Unable to write generated.rs");

            let mut gen_writer = BufWriter::new(gen_file);

            codegen::generator::generate_source(&service, &mut gen_writer).unwrap();

            let custom_dir_path = src_dir.join("custom");

            if !custom_dir_path.exists() {
                fs::create_dir(&custom_dir_path).expect(&format!("Unable to create directory at {}", custom_dir_path.display()));
            }

            let custom_mod_file_path = custom_dir_path.join("mod.rs");

            if !custom_mod_file_path.exists() {
                OpenOptions::new()
                    .write(true)
                    .create_new(true)
                    .open(&custom_mod_file_path)
                    .expect("Unable to write mod.rs");
            }
        }

        {
            let src_dir = crate_dir.join("src");
            let gen_file_path = src_dir.join("generated.rs");

            let _ = rustfmt::run(rustfmt::Input::File(gen_file_path), &rustfmt::config::Config {
                write_mode: rustfmt::config::WriteMode::Overwrite,
                error_on_line_overflow: false,
                ..rustfmt::config::Config::default()
            });
        }

        {
            let test_resources_dir = crate_dir.join("test_resources");

            if !test_resources_dir.exists() {
                fs::create_dir(&test_resources_dir).expect(&format!("Unable to create directory at {}", test_resources_dir.display()));
            }

            let generated_test_resources_dir = test_resources_dir.join("generated");

            if !generated_test_resources_dir.exists() {
                fs::create_dir(&generated_test_resources_dir).expect(&format!("Unable to create directory at {}", generated_test_resources_dir.display()));
            }

            let test_valid_resources = codegen::generator::tests::find_valid_responses_for_service(&service);
            if !test_valid_resources.is_empty() {
                let test_valid_resources_dir = generated_test_resources_dir.join("valid");

                if !test_valid_resources_dir.exists() {
                    fs::create_dir(&test_valid_resources_dir).expect(&format!("Unable to create directory at {}", generated_test_resources_dir.display()));
                }

                for resource in test_valid_resources {
                    fs::copy(resource.full_path, test_valid_resources_dir.join(&resource.file_name)).expect("Failed to copy test resource file");
                }
            }

            let test_error_resources = codegen::generator::tests::find_error_responses_for_service(&service);
            if !test_error_resources.is_empty() {
                let test_error_resources_dir = generated_test_resources_dir.join("error");

                if !test_error_resources_dir.exists() {
                    fs::create_dir(&test_error_resources_dir).expect(&format!("Unable to create directory at {}", generated_test_resources_dir.display()));
                }

                for resource in test_error_resources {
                    fs::copy(resource.full_path, test_error_resources_dir.join(&resource.file_name)).expect("Failed to copy test resource file");
                }
            }
        }
    });
}
<commit_msg>Trim crate keyword if the service name is too long.<commit_after>#![cfg_attr(feature = "nightly-testing", feature(plugin))]
#![cfg_attr(feature = "nightly-testing", plugin(clippy))]

#[macro_use]
extern crate clap;
extern crate rayon;
extern crate rustfmt;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;
extern crate inflector;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate hyper;

mod cargo;
mod codegen;
mod config;
mod service;

use std::fs::{self, OpenOptions};
use std::io::{Write, BufWriter};
use std::path::Path;

use rayon::prelude::*;

use clap::{Arg, App};

use codegen::botocore::{ServiceDefinition};
pub use service::Service;
use config::ServiceConfig;

fn main() {
    let matches = App::new("Rusoto Service Crate Generator")
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("services_config")
            .long("config")
            .short("c")
            .takes_value(true))
        .arg(Arg::with_name("out_dir")
            .long("outdir")
            .short("o")
            .takes_value(true)
            .required(true))
        .get_matches();

    let out_dir = Path::new(matches.value_of("out_dir").unwrap());

    if !out_dir.exists() {
        fs::create_dir(out_dir).expect("Unable to create output directory");
    }

    let services_config_path = matches.value_of("services_config").unwrap();
    let service_configs = ServiceConfig::load_all(services_config_path).expect("Unable to read services configuration file.");

    service_configs.par_iter().for_each(|&(ref name, ref service_config)| {
        let service = {
            let service_definition = ServiceDefinition::load(name, &service_config.protocol_version)
                .expect(&format!("Failed to load service {}. Make sure the botocore submodule has been initialized!", name));
            Service::new(service_config.clone(), service_definition)
        };

        let crate_dir = out_dir.join(&name);
        let crate_name = format!("rusoto_{}", &name.replace('-', "_"));

        println!("Generating crate for {} @ {}...", service.full_name(), service.api_version());

        if !crate_dir.exists() {
            fs::create_dir(&crate_dir).expect(&format!("Unable to create directory at {}", crate_dir.display()));
        }

        let service_dependencies = service.get_dependencies();

        let extern_crates = service_dependencies.iter().map(|(k, _)| {
            if k == "xml-rs" {
                return "extern crate xml;".into();
            }
            let safe_name = k.replace("-", "_");
            let use_macro = k == "serde_derive" || k == "log" || k == "lazy_static";
            if use_macro {
                return format!("#[macro_use]\nextern crate {};", safe_name);
            }
            format!("extern crate {};", safe_name)
        }).collect::<Vec<String>>().join("\n");

        let mut cargo_manifest = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(crate_dir.join("Cargo.toml"))
            .expect("Unable to write Cargo.toml");

        // crates.io has a max of 20 chars for keywords, do an ugly truncate if needed:
        let mut name_for_keyword = name.clone().to_string();
        if name_for_keyword.len() >= 20 {
            name_for_keyword = name_for_keyword[..20].to_string();
        }

        let manifest = cargo::Manifest {
            package: cargo::Metadata {
                authors: Some(vec![
                    "Anthony DiMarco <ocramida@gmail.com>".into(),
                    "Jimmy Cuadra <jimmy@jimmycuadra.com>".into(),
                    "Matthew Mayer <matthewkmayer@gmail.com>".into(),
                    "Nikita Pekin <contact@nikitapek.in>".into()
                ]),
                description: Some(format!("AWS SDK for Rust - {} @ {}", service.full_name(), service.api_version())),
                documentation: Some("https://rusoto.github.io/rusoto/rusoto_core/index.html".into()),
                keywords: Some(vec!["AWS".into(), "Amazon".into(), name_for_keyword]),
                license: Some("MIT".into()),
                name: crate_name.clone(),
                readme: Some("README.md".into()),
                repository: Some("https://github.com/rusoto/rusoto".into()),
                version: service_config.version.clone(),
                homepage: Some("https://www.rusoto.org/".into()),
                ..cargo::Metadata::default()
            },
            dependencies: service_dependencies,
            dev_dependencies: vec![
                ("rusoto_mock".to_owned(), cargo::Dependency::Extended {
                    path: Some("../../../mock".into()),
                    version: Some("0.24.0".into()),
                    optional: None,
                    default_features: None,
                    features: None
                })
            ].into_iter().collect(),
            ..cargo::Manifest::default()
        };

        cargo_manifest.write_all(toml::to_string(&manifest).unwrap().as_bytes()).unwrap();

        let mut readme_file = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(crate_dir.join("README.md"))
            .expect("Unable to write README.md");

        let readme = format!(r#"
# Rusoto {short_name}
Rust SDK for {aws_name}

You may be looking for:

* [An overview of Rusoto][rusoto-overview]
* [AWS services supported by Rusoto][supported-aws-services]
* [API documentation][api-documentation]
* [Getting help with Rusoto][rusoto-help]

## Requirements

Rust stable or beta are required to use Rusoto. Nightly is tested, but not guaranteed to be supported. Older
versions _may_ be supported. The currently supported Rust versions can be found in the Rusoto project
[`travis.yml`](https://github.com/rusoto/rusoto/blob/master/.travis.yml).

On Linux, OpenSSL is required.

## Installation

To use `{crate_name}` in your application, add it as a dependency in your `Cargo.toml`:

```toml
[dependencies]
{crate_name} = "{version}"
```

## Contributing

See [CONTRIBUTING][contributing].

## License

Rusoto is distributed under the terms of the MIT license.

See [LICENSE][license] for details.

[api-documentation]: https://rusoto.github.io/rusoto/rusoto/ "API documentation"
[license]: https://github.com/rusoto/rusoto/blob/master/LICENSE "MIT License"
[contributing]: https://github.com/rusoto/rusoto/blob/master/CONTRIBUTING.md "Contributing Guide"
[rusoto-help]: https://www.rusoto.org/help.html "Getting help with Rusoto"
[rusoto-overview]: https://www.rusoto.org/ "Rusoto overview"
[supported-aws-services]: https://www.rusoto.org/supported-aws-services.html "List of AWS services supported by Rusoto"
        "#,
        short_name = service.service_type_name(),
        aws_name = service.full_name(),
        crate_name = crate_name,
        version = service_config.version
        );

        readme_file.write_all(readme.as_bytes()).unwrap();

        {
            let src_dir = crate_dir.join("src");

            if !src_dir.exists() {
                fs::create_dir(&src_dir).expect(&format!("Unable to create directory at {}", src_dir.display()));
            }

            let lib_file_path = src_dir.join("lib.rs");

            let mut lib_file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(&lib_file_path)
                .expect("Unable to write lib.rs");

            let lib_file_contents = format!(r#"
//! {service_full_name}
//!
//! If you're using the service, you're probably looking for [{client_name}](struct.{client_name}.html) and [{trait_name}](trait.{trait_name}.html).

{extern_crates}

mod generated;
mod custom;

pub use generated::*;
pub use custom::*;
            "#,
            service_full_name = service.full_name(),
            client_name = service.client_type_name(),
            trait_name = service.service_type_name(),
            extern_crates = extern_crates
            );

            lib_file.write_all(lib_file_contents.as_bytes()).unwrap();

            let gen_file_path = src_dir.join("generated.rs");

            let gen_file = OpenOptions::new()
                .create(true)
                .write(true)
                .truncate(true)
                .open(&gen_file_path)
                .expect("Unable to write generated.rs");

            let mut gen_writer = BufWriter::new(gen_file);

            codegen::generator::generate_source(&service, &mut gen_writer).unwrap();

            let custom_dir_path = src_dir.join("custom");

            if !custom_dir_path.exists() {
                fs::create_dir(&custom_dir_path).expect(&format!("Unable to create directory at {}", custom_dir_path.display()));
            }

            let custom_mod_file_path = custom_dir_path.join("mod.rs");

            if !custom_mod_file_path.exists() {
                OpenOptions::new()
                    .write(true)
                    .create_new(true)
                    .open(&custom_mod_file_path)
                    .expect("Unable to write mod.rs");
            }
        }

        {
            let src_dir = crate_dir.join("src");
            let gen_file_path = src_dir.join("generated.rs");

            let _ = rustfmt::run(rustfmt::Input::File(gen_file_path), &rustfmt::config::Config {
                write_mode: rustfmt::config::WriteMode::Overwrite,
                error_on_line_overflow: false,
                ..rustfmt::config::Config::default()
            });
        }

        {
            let test_resources_dir = crate_dir.join("test_resources");

            if !test_resources_dir.exists() {
                fs::create_dir(&test_resources_dir).expect(&format!("Unable to create directory at {}", test_resources_dir.display()));
            }

            let generated_test_resources_dir = test_resources_dir.join("generated");

            if !generated_test_resources_dir.exists() {
                fs::create_dir(&generated_test_resources_dir).expect(&format!("Unable to create directory at {}", generated_test_resources_dir.display()));
            }

            let test_valid_resources = codegen::generator::tests::find_valid_responses_for_service(&service);
            if !test_valid_resources.is_empty() {
                let test_valid_resources_dir = generated_test_resources_dir.join("valid");

                if !test_valid_resources_dir.exists() {
                    fs::create_dir(&test_valid_resources_dir).expect(&format!("Unable to create directory at {}", generated_test_resources_dir.display()));
                }

                for resource in test_valid_resources {
                    fs::copy(resource.full_path, test_valid_resources_dir.join(&resource.file_name)).expect("Failed to copy test resource file");
                }
            }

            let test_error_resources = codegen::generator::tests::find_error_responses_for_service(&service);
            if !test_error_resources.is_empty() {
                let test_error_resources_dir = generated_test_resources_dir.join("error");

                if !test_error_resources_dir.exists() {
                    fs::create_dir(&test_error_resources_dir).expect(&format!("Unable to create directory at {}", generated_test_resources_dir.display()));
                }

                for resource in test_error_resources {
                    fs::copy(resource.full_path, test_error_resources_dir.join(&resource.file_name)).expect("Failed to copy test resource file");
                }
            }
        }
    });
}
<|endoftext|>


<commit_before>#!/usr/bin/env rustx

use std;

fn main () {
   io::println("Hello!");
}

#[test]
fn test () {
   assert 2 + 2 == 4;
}

<commit_msg>change to crate syntax<commit_after>#!/usr/bin/env rustx

extern mod std;

fn main () {
   io::println("Hello!");
}

#[test]
fn test () {
   assert 2 + 2 == 4;
}

<|endoftext|>


<commit_before>use crate::{
    frame::{AMQPFrame, ProtocolVersion},
    protocol::{basic::gen_properties, *},
    types::{generation::*, *},
};
use cookie_factory::{combinator::slice, sequence::tuple};
use std::io::Write;

/// Serialize a frame in the given buffer
pub fn gen_frame<'a, W: Write + BackToTheBuffer + 'a>(
    frame: &'a AMQPFrame,
) -> impl SerializeFn<W> + 'a {
    move |x| match frame {
        AMQPFrame::ProtocolHeader(version) => gen_protocol_header(version)(x),
        AMQPFrame::Heartbeat(channel_id) => gen_heartbeat_frame(*channel_id)(x),
        AMQPFrame::Method(channel_id, method) => gen_method_frame(*channel_id, method)(x),
        AMQPFrame::Header(channel_id, class_id, header) => {
            gen_content_header_frame(*channel_id, *class_id, header.body_size, &header.properties)(
                x,
            )
        }
        AMQPFrame::Body(channel_id, data) => gen_content_body_frame(*channel_id, data)(x),
    }
}

fn gen_protocol_header<W: Write>(version: &ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        slice(metadata::NAME.as_bytes()),
        gen_short_short_uint(0),
        gen_protocol_version(version),
    ))
}

fn gen_protocol_version<W: Write>(version: &ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        gen_short_short_uint(version.major),
        gen_short_short_uint(version.minor),
        gen_short_short_uint(version.revision),
    ))
}

fn gen_heartbeat_frame<W: Write>(channel_id: ShortUInt) -> impl SerializeFn<W> {
    tuple((
        gen_short_short_uint(constants::FRAME_HEARTBEAT),
        gen_id(channel_id),
        gen_long_uint(0),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_method_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class: &'a AMQPClass,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_METHOD),
        gen_id(channel_id),
        gen_with_len(gen_class(class)),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_header_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class_id: ShortUInt,
    length: LongLongUInt,
    properties: &'a basic::AMQPProperties,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_HEADER),
        gen_id(channel_id),
        gen_with_len(tuple((
            gen_id(class_id),
            gen_short_uint(0 /* weight */),
            gen_long_long_uint(length),
            gen_properties(properties),
        ))),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_body_frame<'a, W: Write + 'a>(
    channel_id: ShortUInt,
    content: &'a [u8],
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_BODY),
        gen_id(channel_id),
        gen_long_uint(content.len() as LongUInt),
        slice(content),
        gen_short_short_uint(constants::FRAME_END),
    ))
}
<commit_msg>silence clippy<commit_after>use crate::{
    frame::{AMQPFrame, ProtocolVersion},
    protocol::{basic::gen_properties, *},
    types::{generation::*, *},
};
use cookie_factory::{combinator::slice, sequence::tuple};
use std::io::Write;

/// Serialize a frame in the given buffer
pub fn gen_frame<'a, W: Write + BackToTheBuffer + 'a>(
    frame: &'a AMQPFrame,
) -> impl SerializeFn<W> + 'a {
    move |x| match frame {
        AMQPFrame::ProtocolHeader(version) => gen_protocol_header(*version)(x),
        AMQPFrame::Heartbeat(channel_id) => gen_heartbeat_frame(*channel_id)(x),
        AMQPFrame::Method(channel_id, method) => gen_method_frame(*channel_id, method)(x),
        AMQPFrame::Header(channel_id, class_id, header) => {
            gen_content_header_frame(*channel_id, *class_id, header.body_size, &header.properties)(
                x,
            )
        }
        AMQPFrame::Body(channel_id, data) => gen_content_body_frame(*channel_id, data)(x),
    }
}

fn gen_protocol_header<W: Write>(version: ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        slice(metadata::NAME.as_bytes()),
        gen_short_short_uint(0),
        gen_protocol_version(version),
    ))
}

fn gen_protocol_version<W: Write>(version: ProtocolVersion) -> impl SerializeFn<W> {
    tuple((
        gen_short_short_uint(version.major),
        gen_short_short_uint(version.minor),
        gen_short_short_uint(version.revision),
    ))
}

fn gen_heartbeat_frame<W: Write>(channel_id: ShortUInt) -> impl SerializeFn<W> {
    tuple((
        gen_short_short_uint(constants::FRAME_HEARTBEAT),
        gen_id(channel_id),
        gen_long_uint(0),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_method_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class: &'a AMQPClass,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_METHOD),
        gen_id(channel_id),
        gen_with_len(gen_class(class)),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_header_frame<'a, W: Write + BackToTheBuffer + 'a>(
    channel_id: ShortUInt,
    class_id: ShortUInt,
    length: LongLongUInt,
    properties: &'a basic::AMQPProperties,
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_HEADER),
        gen_id(channel_id),
        gen_with_len(tuple((
            gen_id(class_id),
            gen_short_uint(0 /* weight */),
            gen_long_long_uint(length),
            gen_properties(properties),
        ))),
        gen_short_short_uint(constants::FRAME_END),
    ))
}

fn gen_content_body_frame<'a, W: Write + 'a>(
    channel_id: ShortUInt,
    content: &'a [u8],
) -> impl SerializeFn<W> + 'a {
    tuple((
        gen_short_short_uint(constants::FRAME_BODY),
        gen_id(channel_id),
        gen_long_uint(content.len() as LongUInt),
        slice(content),
        gen_short_short_uint(constants::FRAME_END),
    ))
}
<|endoftext|>