<commit_before>//! This module provides the logic necessary to implement a license prompt into
//! the hab CLI. When a user runs hab for the first time, they will be prompted
//! to accept the Chef license agreement. If they choose not to, then hab will
//! exit and they will be unable to use the tool.
//!
//! Choosing to accept the license will write a file to either
//! /hab/accepted-licenses/habitat (if run as root) or
//! ~/.hab/accepted-licenses/habitat. The presence of this file will
//! prevent further license prompts. The file itself contains various metadata
//! that we collect, but it's important to note that the contents of this file
//! are not strictly important. The important thing is the presence of the file.
//!
//! If a user was to read our code and pre-emptively create one of the above
//! files and leave its contents completely empty, that is sufficient for the
//! acceptance of the license. We will not overwrite their empty file, nor
//! will we care that it is empty.
//!
//! Because of this, the metadata that we store is not strictly necessary and
//! is more of a best effort scenario. If we can't collect all of it for
//! whatever reason, it's fine.
//!
//! Additionally, there are 2 environment variables that are supported to
//! constitute license acceptance. Setting HAB_LICENSE to "accept" will
//! accept the license and persist the file and setting HAB_LICENSE to
//! "accept-no-persist" will accept the license but not persist the
//! acceptance.
//!
//! More detailed information on the license spec is available at
//! https://github.com/chef/license-acceptance

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::prelude::*;
use dirs;
use serde_yaml;
use std::{env,
          fs::{self,
               File},
          io::Write,
          path::PathBuf};

const LICENSE_FILE_FORMAT_VERSION: &str = "1.0";
const LICENSE_ACCEPT_ENVVAR: &str = "HAB_LICENSE";

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from(LICENSE_FILE_FORMAT_VERSION), }
    }
}

pub fn check_for_license_acceptance() -> Result<bool> {
    if license_exists() || env_var_present()? {
        return Ok(true);
    }

    Ok(false)
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if check_for_license_acceptance()? {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    write_license_file()?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn superuser_license_root() -> PathBuf { PathBuf::from(&*FS_ROOT_PATH).join("hab") }

fn user_license_root() -> PathBuf {
    if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        panic!("No home directory available. Unable to find a suitable place to write a license \
                file.");
    }
}

fn license_path(root_path: &PathBuf) -> PathBuf { root_path.join("accepted-licenses") }

fn license_file(license_path: &PathBuf) -> PathBuf { license_path.join("habitat") }

fn writeable_license_path() -> PathBuf {
    let root_dir = if am_i_root() {
        superuser_license_root()
    } else {
        user_license_root()
    };

    license_path(&root_dir)
}

fn env_var_present() -> Result<bool> {
    match env::var(LICENSE_ACCEPT_ENVVAR) {
        Ok(val) => {
            if &val == "accept" {
                write_license_file()?;
                Ok(true)
            } else if &val == "accept-no-persist" {
                Ok(true)
            } else {
                Ok(false)
            }
        }
        Err(_) => Ok(false),
    }
}

fn write_license_file() -> Result<()> {
    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(writeable_license_path())?;
    let mut file = File::create(license_file(&writeable_license_path()))?;
    file.write_all(content.as_bytes())?;
    Ok(())
}

pub fn license_exists() -> bool {
    license_file(&license_path(&superuser_license_root())).is_file()
    || license_file(&license_path(&user_license_root())).is_file()
}
<commit_msg>Check the user license first, then superuser<commit_after>//! This module provides the logic necessary to implement a license prompt into
//! the hab CLI. When a user runs hab for the first time, they will be prompted
//! to accept the Chef license agreement. If they choose not to, then hab will
//! exit and they will be unable to use the tool.
//!
//! Choosing to accept the license will write a file to either
//! /hab/accepted-licenses/habitat (if run as root) or
//! ~/.hab/accepted-licenses/habitat. The presence of this file will
//! prevent further license prompts. The file itself contains various metadata
//! that we collect, but it's important to note that the contents of this file
//! are not strictly important. The important thing is the presence of the file.
//!
//! If a user was to read our code and pre-emptively create one of the above
//! files and leave its contents completely empty, that is sufficient for the
//! acceptance of the license. We will not overwrite their empty file, nor
//! will we care that it is empty.
//!
//! Because of this, the metadata that we store is not strictly necessary and
//! is more of a best effort scenario. If we can't collect all of it for
//! whatever reason, it's fine.
//!
//! Additionally, there are 2 environment variables that are supported to
//! constitute license acceptance. Setting HAB_LICENSE to "accept" will
//! accept the license and persist the file and setting HAB_LICENSE to
//! "accept-no-persist" will accept the license but not persist the
//! acceptance.
//!
//! More detailed information on the license spec is available at
//! https://github.com/chef/license-acceptance

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::prelude::*;
use dirs;
use serde_yaml;
use std::{env,
          fs::{self,
               File},
          io::Write,
          path::PathBuf};

const LICENSE_FILE_FORMAT_VERSION: &str = "1.0";
const LICENSE_ACCEPT_ENVVAR: &str = "HAB_LICENSE";

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from(LICENSE_FILE_FORMAT_VERSION), }
    }
}

pub fn check_for_license_acceptance() -> Result<bool> {
    if license_exists() || env_var_present()? {
        return Ok(true);
    }

    Ok(false)
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if check_for_license_acceptance()? {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    write_license_file()?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn superuser_license_root() -> PathBuf { PathBuf::from(&*FS_ROOT_PATH).join("hab") }

fn user_license_root() -> PathBuf {
    if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        panic!("No home directory available. Unable to find a suitable place to write a license \
                file.");
    }
}

fn license_path(root_path: &PathBuf) -> PathBuf { root_path.join("accepted-licenses") }

fn license_file(license_path: &PathBuf) -> PathBuf { license_path.join("habitat") }

fn writeable_license_path() -> PathBuf {
    let root_dir = if am_i_root() {
        superuser_license_root()
    } else {
        user_license_root()
    };

    license_path(&root_dir)
}

fn env_var_present() -> Result<bool> {
    match env::var(LICENSE_ACCEPT_ENVVAR) {
        Ok(val) => {
            if &val == "accept" {
                write_license_file()?;
                Ok(true)
            } else if &val == "accept-no-persist" {
                Ok(true)
            } else {
                Ok(false)
            }
        }
        Err(_) => Ok(false),
    }
}

fn write_license_file() -> Result<()> {
    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(writeable_license_path())?;
    let mut file = File::create(license_file(&writeable_license_path()))?;
    file.write_all(content.as_bytes())?;
    Ok(())
}

pub fn license_exists() -> bool {
    license_file(&license_path(&user_license_root())).is_file()
    || license_file(&license_path(&superuser_license_root())).is_file()
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use devtools_traits;
use devtools_traits::{EvaluateJSReply, NodeInfo, Modification};
use dom::bindings::conversions;
use dom::bindings::conversions::FromJSValConvertible;
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::DOMRectBinding::{DOMRectMethods};
use dom::bindings::codegen::Bindings::ElementBinding::{ElementMethods};
use dom::node::{Node, NodeHelpers};
use dom::window::{WindowHelpers};
use dom::element::Element;
use dom::document::DocumentHelpers;
use page::Page;
use servo_msg::constellation_msg::PipelineId;
use script_task::get_page;
use std::rc::Rc;

pub fn handle_evaluate_js(page: &Rc<Page>, pipeline: PipelineId, eval: String, reply: Sender<EvaluateJSReply>){
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let window = frame.as_ref().unwrap().window.root();
    let cx = window.get_cx();
    let rval = window.evaluate_js_with_result(eval.as_slice());

    reply.send(if rval.is_undefined() {
        devtools_traits::VoidValue
    } else if rval.is_boolean() {
        devtools_traits::BooleanValue(rval.to_boolean())
    } else if rval.is_double() {
        devtools_traits::NumberValue(FromJSValConvertible::from_jsval(cx, rval, ()).unwrap())
    } else if rval.is_string() {
        //FIXME: use jsstring_to_str when jsval grows to_jsstring
        devtools_traits::StringValue(FromJSValConvertible::from_jsval(cx, rval, conversions::Default).unwrap())
    } else {
        //FIXME: jsvals don't have an is_int32/is_number yet
        assert!(rval.is_object_or_null());
        panic!("object values unimplemented")
    });
}

pub fn handle_get_root_node(page: &Rc<Page>, pipeline: PipelineId, reply: Sender<NodeInfo>) {
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let document = frame.as_ref().unwrap().document.root();

    let node: JSRef<Node> = NodeCast::from_ref(*document);
    reply.send(node.summarize());
}

pub fn handle_get_document_element(page: &Rc<Page>, pipeline: PipelineId, reply: Sender<NodeInfo>) {
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let document = frame.as_ref().unwrap().document.root();
    let document_element = document.GetDocumentElement().root().unwrap();

    let node: JSRef<Node> = NodeCast::from_ref(*document_element);
    reply.send(node.summarize());
}

fn find_node_by_unique_id(page: &Rc<Page>, pipeline: PipelineId, node_id: String) -> Temporary<Node> {
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let document = frame.as_ref().unwrap().document.root();
    let node: JSRef<Node> = NodeCast::from_ref(*document);

    for candidate in node.traverse_preorder() {
        if candidate.get_unique_id().as_slice() == node_id.as_slice() {
            return Temporary::from_rooted(candidate);
        }
    }

    panic!("couldn't find node with unique id {:s}", node_id)
}

pub fn handle_get_children(page: &Rc<Page>, pipeline: PipelineId, node_id: String, reply: Sender<Vec<NodeInfo>>) {
    let parent = find_node_by_unique_id(&*page, pipeline, node_id).root();
    let children = parent.children().map(|child| child.summarize()).collect();
    reply.send(children);
}

pub fn handle_get_layout(page: &Rc<Page>, pipeline: PipelineId, node_id: String, reply: Sender<(f32, f32)>) {
    let node = find_node_by_unique_id(&*page, pipeline, node_id).root();
    let elem: JSRef<Element> = ElementCast::to_ref(*node).expect("should be getting layout of element");
    let rect = elem.GetBoundingClientRect().root();
    reply.send((rect.Width(), rect.Height()));
}

pub fn handle_modify_attribute(page: &Rc<Page>, pipeline: PipelineId, node_id: String, modifications: Vec<Modification>) {
    let node = find_node_by_unique_id(&*page, pipeline, node_id).root();
    let elem: JSRef<Element> = ElementCast::to_ref(*node).expect("should be getting layout of element");

    for modification in modifications.iter(){
        match modification.newValue {
            Some(ref string) => {
                let _ = elem.SetAttribute(modification.attributeName.clone(), string.clone());
            },
            None => elem.RemoveAttribute(modification.attributeName.clone()),
        }
    }
}
<commit_msg>handle null for evaluating JS value. #4235<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use devtools_traits;
use devtools_traits::{EvaluateJSReply, NodeInfo, Modification};
use dom::bindings::conversions;
use dom::bindings::conversions::FromJSValConvertible;
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::DOMRectBinding::{DOMRectMethods};
use dom::bindings::codegen::Bindings::ElementBinding::{ElementMethods};
use dom::node::{Node, NodeHelpers};
use dom::window::{WindowHelpers};
use dom::element::Element;
use dom::document::DocumentHelpers;
use page::Page;
use servo_msg::constellation_msg::PipelineId;
use script_task::get_page;
use std::rc::Rc;

pub fn handle_evaluate_js(page: &Rc<Page>, pipeline: PipelineId, eval: String, reply: Sender<EvaluateJSReply>){
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let window = frame.as_ref().unwrap().window.root();
    let cx = window.get_cx();
    let rval = window.evaluate_js_with_result(eval.as_slice());

    reply.send(if rval.is_undefined() {
        devtools_traits::VoidValue
    } else if rval.is_boolean() {
        devtools_traits::BooleanValue(rval.to_boolean())
    } else if rval.is_double() {
        devtools_traits::NumberValue(FromJSValConvertible::from_jsval(cx, rval, ()).unwrap())
    } else if rval.is_string() {
        //FIXME: use jsstring_to_str when jsval grows to_jsstring
        devtools_traits::StringValue(FromJSValConvertible::from_jsval(cx, rval, conversions::Default).unwrap())
    } else if rval.is_null() {
        devtools_traits::NullValue
    } else {
        //FIXME: jsvals don't have an is_int32/is_number yet
        assert!(rval.is_object());
        panic!("object values unimplemented")
    });
}

pub fn handle_get_root_node(page: &Rc<Page>, pipeline: PipelineId, reply: Sender<NodeInfo>) {
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let document = frame.as_ref().unwrap().document.root();

    let node: JSRef<Node> = NodeCast::from_ref(*document);
    reply.send(node.summarize());
}

pub fn handle_get_document_element(page: &Rc<Page>, pipeline: PipelineId, reply: Sender<NodeInfo>) {
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let document = frame.as_ref().unwrap().document.root();
    let document_element = document.GetDocumentElement().root().unwrap();

    let node: JSRef<Node> = NodeCast::from_ref(*document_element);
    reply.send(node.summarize());
}

fn find_node_by_unique_id(page: &Rc<Page>, pipeline: PipelineId, node_id: String) -> Temporary<Node> {
    let page = get_page(&*page, pipeline);
    let frame = page.frame();
    let document = frame.as_ref().unwrap().document.root();
    let node: JSRef<Node> = NodeCast::from_ref(*document);

    for candidate in node.traverse_preorder() {
        if candidate.get_unique_id().as_slice() == node_id.as_slice() {
            return Temporary::from_rooted(candidate);
        }
    }

    panic!("couldn't find node with unique id {:s}", node_id)
}

pub fn handle_get_children(page: &Rc<Page>, pipeline: PipelineId, node_id: String, reply: Sender<Vec<NodeInfo>>) {
    let parent = find_node_by_unique_id(&*page, pipeline, node_id).root();
    let children = parent.children().map(|child| child.summarize()).collect();
    reply.send(children);
}

pub fn handle_get_layout(page: &Rc<Page>, pipeline: PipelineId, node_id: String, reply: Sender<(f32, f32)>) {
    let node = find_node_by_unique_id(&*page, pipeline, node_id).root();
    let elem: JSRef<Element> = ElementCast::to_ref(*node).expect("should be getting layout of element");
    let rect = elem.GetBoundingClientRect().root();
    reply.send((rect.Width(), rect.Height()));
}

pub fn handle_modify_attribute(page: &Rc<Page>, pipeline: PipelineId, node_id: String, modifications: Vec<Modification>) {
    let node = find_node_by_unique_id(&*page, pipeline, node_id).root();
    let elem: JSRef<Element> = ElementCast::to_ref(*node).expect("should be getting layout of element");

    for modification in modifications.iter(){
        match modification.newValue {
            Some(ref string) => {
                let _ = elem.SetAttribute(modification.attributeName.clone(), string.clone());
            },
            None => elem.RemoveAttribute(modification.attributeName.clone()),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate diesel;

mod config;
mod database;
mod err;
mod file;
mod series;
mod tui;
mod util;

use crate::config::Config;
use crate::database::Database;
use crate::err::{Error, Result};
use crate::file::TomlFile;
use crate::series::config::SeriesConfig;
use crate::series::entry::SeriesEntry;
use crate::series::info::SeriesInfo;
use crate::series::{LastWatched, Series, SeriesData, SeriesParams};
use anime::remote::RemoteService;
use chrono::Utc;
use gumdrop::Options;
use snafu::{ensure, ResultExt};
use std::path::PathBuf;
use std::str;

const ANILIST_CLIENT_ID: u32 = 427;
const SERIES_TITLE_REP: &str = "{title}";
const SERIES_EPISODE_REP: &str = "{episode}";

#[derive(Options)]
pub struct CmdOptions {
    #[options(help = "print help message")]
    help: bool,
    #[options(free, help = "the nickname of the series to watch")]
    pub series: Option<String>,
    #[options(help = "run in offline mode")]
    pub offline: bool,
    #[options(help = "play a single episode from the specified or last watched series")]
    pub single: bool,
    #[options(help = "your account access token")]
    pub token: Option<String>,
    #[options(no_short, help = "the ID to use for the series")]
    pub series_id: Option<i32>,
    #[options(
        no_short,
        help = "the custom regex pattern to match episode files with"
    )]
    pub matcher: Option<String>,
    #[options(no_short, help = "the path to the series")]
    pub path: Option<PathBuf>,
    #[options(
        no_short,
        help = "fetch series info from AniList for use with offline mode"
    )]
    pub prefetch: bool,
    #[options(no_short, help = "syncronize changes made while offline to AniList")]
    pub sync: bool,
}

fn main() {
    let args = CmdOptions::parse_args_default_or_exit();

    if let Err(err) = run(args) {
        err::display_error(err);
        std::process::exit(1);
    }
}

fn run(args: CmdOptions) -> Result<()> {
    if args.single {
        play_episode(args)
    } else if args.prefetch {
        prefetch(args)
    } else if args.sync {
        sync(args)
    } else {
        tui::run(args)
    }
}

fn init_remote(args: &CmdOptions, can_use_offline: bool) -> Result<Box<dyn RemoteService>> {
    use anime::remote::anilist::AniList;
    use anime::remote::offline::Offline;
    use anime::remote::AccessToken;

    if args.offline {
        ensure!(can_use_offline, err::MustRunOnline);
        Ok(Box::new(Offline::new()))
    } else {
        let token = match &args.token {
            Some(token) => {
                let token = AccessToken::encode(token);
                token.save()?;
                token
            }
            None => match AccessToken::load() {
                Ok(token) => token,
                Err(ref err) if err.is_file_nonexistant() => {
                    return Err(Error::NeedAniListToken);
                }
                Err(err) => return Err(err),
            },
        };

        let anilist = AniList::authenticated(token)?;
        Ok(Box::new(anilist))
    }
}

fn prefetch(args: CmdOptions) -> Result<()> {
    let desired_series = match &args.series {
        Some(desired_series) => desired_series,
        None => return Err(Error::MustSpecifySeriesName),
    };

    let config = Config::load_or_create()?;
    let db = Database::open()?;
    let params = SeriesParams::from(&args);

    let cfg = match (SeriesConfig::load_by_name(&db, &desired_series), params.id) {
        (Ok(mut cfg), _) => {
            cfg.apply_params(&params, &config, &db)?;
            cfg
        }
        (Err(_), Some(id)) => {
            let path = match &params.path {
                Some(path) => path.clone(),
                None => util::closest_matching_dir(&config.series_dir, &desired_series)?,
            };

            SeriesConfig::from_params(desired_series, id, path, params, &config, &db)?
        }
        (Err(_), None) => return Err(Error::NewSeriesNeedsID),
    };

    let remote = init_remote(&args, false)?;
    let remote = remote.as_ref();

    let info = SeriesInfo::from_remote_by_id(cfg.id, remote)?;
    let data = SeriesData::from_remote(cfg, info, remote)?;
    let series = Series::new(data, &config)?;

    series.save(&db)?;

    println!(
        "{} was fetched\nyou can now watch this series offline",
        series.data.info.title_preferred
    );

    Ok(())
}

fn sync(args: CmdOptions) -> Result<()> {
    let db = Database::open()?;
    let mut list_entries = SeriesEntry::entries_that_need_sync(&db)?;

    if list_entries.is_empty() {
        return Ok(());
    }

    let remote = init_remote(&args, false)?;

    for entry in &mut list_entries {
        match SeriesInfo::load(&db, entry.id()) {
            Ok(info) => println!("{} is being synced..", info.title_preferred),
            Err(err) => eprintln!(
                "warning: failed to get info for anime with ID {}: {}",
                entry.id(),
                err
            ),
        }

        entry.sync_to_remote(remote.as_ref())?;
        entry.save(&db)?;
    }

    Ok(())
}

fn play_episode(args: CmdOptions) -> Result<()> {
    use anime::remote::Status;

    let config = Config::load_or_create()?;
    let db = Database::open()?;
    let mut last_watched = LastWatched::load()?;

    let remote = init_remote(&args, true)?;
    let remote = remote.as_ref();

    let desired_series = args
        .series
        .as_ref()
        .or_else(|| last_watched.get())
        .ok_or(Error::MustSpecifySeriesName)?;

    let mut series = {
        let cfg =
            SeriesConfig::load_by_name(&db, desired_series).map_err(|_| Error::MustAddSeries {
                name: desired_series.clone(),
            })?;

        Series::load_from_config(cfg, &config, &db)?
    };

    if last_watched.set(&series.data.config.nickname) {
        last_watched.save()?;
    }

    series.begin_watching(remote, &config, &db)?;

    let progress_time = series.data.next_watch_progress_time(&config);
    let next_episode_num = series.data.entry.watched_episodes() + 1;

    series
        .play_episode_cmd(next_episode_num as u32, &config)?
        .status()
        .context(err::FailedToPlayEpisode {
            episode: next_episode_num as u32,
        })?;

    if Utc::now() >= progress_time {
        series.episode_completed(remote, &config, &db)?;

        if series.data.entry.status() == Status::Completed {
            println!("{} completed!", series.data.info.title_preferred);
        } else {
            println!(
                "{}/{} of {} completed",
                series.data.entry.watched_episodes(),
                series.data.info.episodes,
                series.data.info.title_preferred
            );
        }
    } else {
        println!("did not watch long enough to count episode as completed");
    }

    Ok(())
}
<commit_msg>anup: Remove series prefetching from the CLI<commit_after>#[macro_use]
extern crate diesel;

mod config;
mod database;
mod err;
mod file;
mod series;
mod tui;
mod util;

use crate::config::Config;
use crate::database::Database;
use crate::err::{Error, Result};
use crate::file::TomlFile;
use crate::series::config::SeriesConfig;
use crate::series::entry::SeriesEntry;
use crate::series::info::SeriesInfo;
use crate::series::{LastWatched, Series};
use anime::remote::RemoteService;
use chrono::Utc;
use gumdrop::Options;
use snafu::{ensure, ResultExt};
use std::path::PathBuf;
use std::str;

const ANILIST_CLIENT_ID: u32 = 427;
const SERIES_TITLE_REP: &str = "{title}";
const SERIES_EPISODE_REP: &str = "{episode}";

#[derive(Options)]
pub struct CmdOptions {
    #[options(help = "print help message")]
    help: bool,
    #[options(free, help = "the nickname of the series to watch")]
    pub series: Option<String>,
    #[options(help = "run in offline mode")]
    pub offline: bool,
    #[options(help = "play a single episode from the specified or last watched series")]
    pub single: bool,
    #[options(help = "your account access token")]
    pub token: Option<String>,
    #[options(no_short, help = "the ID to use for the series")]
    pub series_id: Option<i32>,
    #[options(
        no_short,
        help = "the custom regex pattern to match episode files with"
    )]
    pub matcher: Option<String>,
    #[options(no_short, help = "the path to the series")]
    pub path: Option<PathBuf>,
    #[options(no_short, help = "syncronize changes made while offline to AniList")]
    pub sync: bool,
}

fn main() {
    let args = CmdOptions::parse_args_default_or_exit();

    if let Err(err) = run(args) {
        err::display_error(err);
        std::process::exit(1);
    }
}

fn run(args: CmdOptions) -> Result<()> {
    if args.single {
        play_episode(args)
    } else if args.sync {
        sync(args)
    } else {
        tui::run(args)
    }
}

fn init_remote(args: &CmdOptions, can_use_offline: bool) -> Result<Box<dyn RemoteService>> {
    use anime::remote::anilist::AniList;
    use anime::remote::offline::Offline;
    use anime::remote::AccessToken;

    if args.offline {
        ensure!(can_use_offline, err::MustRunOnline);
        Ok(Box::new(Offline::new()))
    } else {
        let token = match &args.token {
            Some(token) => {
                let token = AccessToken::encode(token);
                token.save()?;
                token
            }
            None => match AccessToken::load() {
                Ok(token) => token,
                Err(ref err) if err.is_file_nonexistant() => {
                    return Err(Error::NeedAniListToken);
                }
                Err(err) => return Err(err),
            },
        };

        let anilist = AniList::authenticated(token)?;
        Ok(Box::new(anilist))
    }
}

fn sync(args: CmdOptions) -> Result<()> {
    let db = Database::open()?;
    let mut list_entries = SeriesEntry::entries_that_need_sync(&db)?;

    if list_entries.is_empty() {
        return Ok(());
    }

    let remote = init_remote(&args, false)?;

    for entry in &mut list_entries {
        match SeriesInfo::load(&db, entry.id()) {
            Ok(info) => println!("{} is being synced..", info.title_preferred),
            Err(err) => eprintln!(
                "warning: failed to get info for anime with ID {}: {}",
                entry.id(),
                err
            ),
        }

        entry.sync_to_remote(remote.as_ref())?;
        entry.save(&db)?;
    }

    Ok(())
}

fn play_episode(args: CmdOptions) -> Result<()> {
    use anime::remote::Status;

    let config = Config::load_or_create()?;
    let db = Database::open()?;
    let mut last_watched = LastWatched::load()?;

    let remote = init_remote(&args, true)?;
    let remote = remote.as_ref();

    let desired_series = args
        .series
        .as_ref()
        .or_else(|| last_watched.get())
        .ok_or(Error::MustSpecifySeriesName)?;

    let mut series = {
        let cfg =
            SeriesConfig::load_by_name(&db, desired_series).map_err(|_| Error::MustAddSeries {
                name: desired_series.clone(),
            })?;

        Series::load_from_config(cfg, &config, &db)?
    };

    if last_watched.set(&series.data.config.nickname) {
        last_watched.save()?;
    }

    series.begin_watching(remote, &config, &db)?;

    let progress_time = series.data.next_watch_progress_time(&config);
    let next_episode_num = series.data.entry.watched_episodes() + 1;

    series
        .play_episode_cmd(next_episode_num as u32, &config)?
        .status()
        .context(err::FailedToPlayEpisode {
            episode: next_episode_num as u32,
        })?;

    if Utc::now() >= progress_time {
        series.episode_completed(remote, &config, &db)?;

        if series.data.entry.status() == Status::Completed {
            println!("{} completed!", series.data.info.title_preferred);
        } else {
            println!(
                "{}/{} of {} completed",
                series.data.entry.watched_episodes(),
                series.data.info.episodes,
                series.data.info.title_preferred
            );
        }
    } else {
        println!("did not watch long enough to count episode as completed");
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! # Example template
//!
//! ```text
//! {% extends "layout.html" %}
//! {% block body %}
//!   <ul>
//!     {% for user in users %}
//!       <li><a href="{{ user.url }}">{{ user.username }}</a></li>
//!     {% endfor %}
//!   </ul>
//! {% endblock %}
//! ```
//!
//! # Feature highlights
//!
//! * Construct templates using a familiar, easy-to-use syntax
//! * Benefit from the safety provided by Rust's type system
//! * Template code is compiled into your crate for optimal performance
//! * Templates only convert your data as needed
//! * Templates can access your Rust types directly, according to Rust's
//!   privacy rules
//! * Debugging features to assist you in template development
//! * Templates must be valid UTF-8 and produce UTF-8 when rendered
//! * Works on stable Rust
//!
//! # Creating Askama templates
//!
//! An Askama template is just a text file, in the UTF-8 encoding.
//! It can be used to generate any kind of text-based format.
//! You can use whatever extension you like.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## Variables
//!
//! Template variables are defined by the template context linked to the
//! template by deriving a `struct`'s implementation for `Template` from
//! a template file's contents.
//! You can use a dot (`.`) to get a variable's attributes.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the ``user``
//! field from the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that a single trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//! A base template must define one or more blocks in order to be enable
//! inheritance. Blocks can only be specified at the top level of a template,
//! not inside `if`/`else` branches or in `for`-loop bodies.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will search for the base template relative to
//! itself before looking relative to the template base directory. It will
//! render the top-level content from the base template, and substitute
//! blocks from the base template with those from the child template. The
//! inheriting template context `struct` must have a field called `_parent` of
//! the type used as the base template context. Blocks can refer to the context
//! of both parent and child template.
//!
//! Note that, if the base template lives in another module than the child
//! template, the child template's module should import all symbols from the
//! base template's module in order for it to find the trait definition that
//! supports the inheritance mechanism.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ### Include
//!
//! The *include* statement lets you split large or repetitive blocks into
//! separate template files. Included templates get full access to the context
//! in which they're used, including local variables like those from loops:
//!
//! ```text
//! {% for i in iter %}
//!   {% include "item.html" %}
//! {% endfor %}
//! ```
//!
//! ```text
//! * Item: {{ i }}
//! ```
//!
//! The path to include must be a string literal, so that it is known at
//! compile time. Askama will try to find the specified template relative
//! to the including template's path before falling back to the absolute
//! template path. Use `include` within the branches of an `if`/`else`
//! block to use includes more dynamically.
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The parser applies the same precedence order as the Rust compiler.
//! Expressions can be grouped using parentheses.
//! The HTML special characters `&`, `<` and `>` will be replaced with their
//! character entities unless the `escape` mode is disabled for a template.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;
extern crate askama_shared as shared;

use shared::path;

use std::fs::{self, DirEntry};
use std::io;
use std::path::Path;

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_into(&self, writer: &mut std::fmt::Write) -> Result<()>;
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> Result<String> {
        let mut buf = String::new();
        self.render_into(&mut buf)?;
        Ok(buf)
    }
}

pub use shared::filters;
pub use askama_derive::*;
pub use shared::{Error, MarkupDisplay, Result};

#[cfg(feature = "with-iron")]
pub mod iron {
    extern crate iron;
    pub use self::iron::modifier::Modifier;
    pub use self::iron::response::Response;
}

#[cfg(feature = "with-rocket")]
pub mod rocket {
    extern crate rocket;
    pub use self::rocket::http::{ContentType, Status};
    pub use self::rocket::request::Request;
    pub use self::rocket::response::{Responder, Response};
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&path::template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<commit_msg>Update feature highlights in documentation<commit_after>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! # Example template
//!
//! ```text
//! {% extends "layout.html" %}
//! {% block body %}
//!   <ul>
//!     {% for user in users %}
//!       <li><a href="{{ user.url }}">{{ user.username }}</a></li>
//!     {% endfor %}
//!   </ul>
//! {% endblock %}
//! ```
//!
//! # Feature highlights
//!
//! * Construct templates using a familiar, easy-to-use syntax
//! * Benefit from the safety provided by Rust's type system
//! * Optional built-in support for Rocket and Iron web frameworks
//! * Template code is compiled into your crate for optimal performance
//! * Templates only convert your data as needed
//! * Templates can access your Rust types directly, according to Rust's privacy rules
//! * Debugging features to assist you in template development
//! * Templates must be valid UTF-8 and produce UTF-8 when rendered
//! * Works on stable Rust
//!
//! # Creating Askama templates
//!
//! An Askama template is just a text file, in the UTF-8 encoding.
//! It can be used to generate any kind of text-based format.
//! You can use whatever extension you like.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## Variables
//!
//! Template variables are defined by the template context linked to the
//! template by deriving a `struct`'s implementation for `Template` from
//! a template file's contents.
//! You can use a dot (`.`) to get a variable's attributes.
//! Reading from variables is subject to the usual borrowing policies.
//! For example, `{{ name }}` will get the ``name`` field from the template
//! context,
//! while `{{ user.name }}` will get the ``name`` field of the ``user``
//! field from the template context.
//!
//! ## Filters
//!
//! Values such as those obtained from variables can be post-processed
//! using **filters**.
//! Filters are applied to values using the pipe symbol (`|`) and may
//! have optional extra arguments in parentheses.
//! Filters can be chained, in which case the output from one filter
//! is passed to the next.
//!
//! For example, `{{ "{:?}"|format(name|escape) }}` will escape HTML
//! characters from the value obtained by accessing the `name` field,
//! and print the resulting string as a Rust literal.
//!
//! Consult the [filters module documentation](filters/index.html) for a list
//! of available filters.
//!
//! ## Whitespace control
//!
//! Askama preserves all whitespace in template code by default,
//! except that a single trailing newline characters are suppressed.
//! However, whitespace before and after expression and block delimiters
//! can be suppressed by writing a minus sign directly following a
//! start delimiter or leading into an end delimiter.
//! Askama considers all tabs, spaces, newlines and carriage returns to be
//! whitespace.
//!
//! ## Template inheritance
//!
//! Template inheritance allows you to build a base template with common
//! elements that can then be shared by all inheriting templates.
//! A base template defines **blocks** that child templates can then override.
//!
//! ### Base template
//!
//! ```text
//! <!DOCTYPE html>
//! <html lang="en">
//!   <head>
//!     <title>{{ block title %}{{ title }}{% endblock %} - My Site</title>
//!     {% block head %}{% endblock %}
//!   </head>
//!   <body>
//!     <div id="content">
//!       {% block content %}{% endblock %}
//!     </div>
//!   </body>
//! </html>
//! ```
//!
//! The `block` tags define three blocks that can be filled in by child
//! templates. The base template defines a default version of the block.
//! A base template must define one or more blocks in order to be enable
//! inheritance. Blocks can only be specified at the top level of a template,
//! not inside `if`/`else` branches or in `for`-loop bodies.
//!
//! ### Child template
//!
//! Here's an example child template:
//!
//! ```text
//! {% extends "base.html" %}
//!
//! {% block title %}Index{% endblock %}
//!
//! {% block head %}
//!   <style>
//!   </style>
//! {% endblock %}
//!
//! {% block content %}
//!   <h1>Index</h1>
//!   <p>Hello, world!</p>
//! {% endblock %}
//! ```
//!
//! The `extends` tag tells the code generator that this template inherits
//! from another template. It will search for the base template relative to
//! itself before looking relative to the template base directory. It will
//! render the top-level content from the base template, and substitute
//! blocks from the base template with those from the child template. The
//! inheriting template context `struct` must have a field called `_parent` of
//! the type used as the base template context. Blocks can refer to the context
//! of both parent and child template.
//!
//! Note that, if the base template lives in another module than the child
//! template, the child template's module should import all symbols from the
//! base template's module in order for it to find the trait definition that
//! supports the inheritance mechanism.
//!
//! ## HTML escaping
//!
//! Askama does not yet support automatic escaping. Care must be taken to
//! escape content that may contain HTML control characters. You can use
//! the `escape` filter (or its `e` alias) to escape data for use in HTML.
//!
//! ## Control structures
//!
//! ### For
//!
//! Loop over each item in an iterator. For example:
//!
//! ```text
//! <h1>Users</h1>
//! <ul>
//! {% for user in users %}
//!   <li>{{ user.name|e }}</li>
//! {% endfor %}
//! </ul>
//! ```
//!
//! Inside for-loop blocks, some useful variables are accessible:
//!
//! * *loop.index*: current loop iteration (starting from 1)
//! * *loop.index0*: current loop iteration (starting from 0)
//!
//! ### If
//!
//! The *if* statement is used as you might expect:
//!
//! ```text
//! {% if users.len() == 0 %}
//!   No users
//! {% else if users.len() == 1 %}
//!   1 user
//! {% else %}
//!   {{ users.len() }} users
//! {% endif %}
//! ```
//!
//! ### Include
//!
//! The *include* statement lets you split large or repetitive blocks into
//! separate template files. Included templates get full access to the context
//! in which they're used, including local variables like those from loops:
//!
//! ```text
//! {% for i in iter %}
//!   {% include "item.html" %}
//! {% endfor %}
//! ```
//!
//! ```text
//! * Item: {{ i }}
//! ```
//!
//! The path to include must be a string literal, so that it is known at
//! compile time. Askama will try to find the specified template relative
//! to the including template's path before falling back to the absolute
//! template path. Use `include` within the branches of an `if`/`else`
//! block to use includes more dynamically.
//!
//! ## Expressions
//!
//! Askama supports string literals (`"foo"`) and integer literals (`1`).
//! It supports almost all binary operators that Rust supports,
//! including arithmetic, comparison and logic operators.
//! The parser applies the same precedence order as the Rust compiler.
//! Expressions can be grouped using parentheses.
//! The HTML special characters `&`, `<` and `>` will be replaced with their
//! character entities unless the `escape` mode is disabled for a template.

#![allow(unused_imports)]
#[macro_use]
extern crate askama_derive;
extern crate askama_shared as shared;

use shared::path;

use std::fs::{self, DirEntry};
use std::io;
use std::path::Path;

/// Main `Template` trait; implementations are generally derived
pub trait Template {
    /// Renders the template to the given `writer` buffer
    fn render_into(&self, writer: &mut std::fmt::Write) -> Result<()>;
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> Result<String> {
        let mut buf = String::new();
        self.render_into(&mut buf)?;
        Ok(buf)
    }
}

pub use shared::filters;
pub use askama_derive::*;
pub use shared::{Error, MarkupDisplay, Result};

#[cfg(feature = "with-iron")]
pub mod iron {
    extern crate iron;
    pub use self::iron::modifier::Modifier;
    pub use self::iron::response::Response;
}

#[cfg(feature = "with-rocket")]
pub mod rocket {
    extern crate rocket;
    pub use self::rocket::http::{ContentType, Status};
    pub use self::rocket::request::Request;
    pub use self::rocket::response::{Responder, Response};
}

fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

/// Build script helper to rebuild crates if contained templates have changed
///
/// Iterates over all files in the template dir (`templates` in
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
/// of them to stdout.
///
/// This helper method can be used in build scripts (`build.rs`) in crates
/// that have templates, to make sure the crate gets rebuilt when template
/// source code changes.
pub fn rerun_if_templates_changed() {
    visit_dirs(&path::template_dir(), &|e: &DirEntry| {
        println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
    }).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(feature = "unstable")]

extern crate compiletest_rs as compiletest;

use std::env;

fn run_mode(mode: &'static str) {
    let mut config = compiletest::Config::default();

    config.mode = mode.parse().expect("invalid mode");
    config.target_rustcflags = Some("-L deps/target/debug/deps".to_owned());
    if let Ok(name) = env::var("TESTNAME") {
        config.filter = Some(name);
    }
    config.src_base = format!("tests/{}", mode).into();

    compiletest::run_tests(&config);
}

#[test]
fn compile_fail() {
    run_mode("compile-fail");
}
<commit_msg>Simplify compiletest setup<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(feature = "unstable")]

extern crate compiletest_rs as compiletest;

#[test]
fn compile_fail() {
    let config = compiletest::Config {
        mode: compiletest::common::Mode::CompileFail,
        src_base: std::path::PathBuf::from("tests/compile-fail"),
        target_rustcflags: Some("-L deps/target/debug/deps".to_owned()),
        ..Default::default()
    };

    compiletest::run_tests(&config);
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

#![deny(needless_lifetimes)]
#![allow(dead_code)]
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { }
//~^ERROR explicit lifetimes given

fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { }
//~^ERROR explicit lifetimes given

fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) { } // no error, same lifetime on two params

fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) { } // no error, static involved

fn mut_and_static_input(_x: &mut u8, _y: &'static str) { }

fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x }
//~^ERROR explicit lifetimes given

fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { x } // no error, multiple input refs

fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x } // no error, multiple input refs

fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x } // no error, static involved

fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { Ok(x) } // no error

fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() } // no error, two input refs

fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) }
//~^ERROR explicit lifetimes given

// where clause, but without lifetimes
fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) }
//~^ERROR explicit lifetimes given

type Ref<'r> = &'r u8;

fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } // no error, same lifetime on two params

fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { }
//~^ERROR explicit lifetimes given

fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounded lifetime

fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a { } // no error, bounded lifetime

struct Lt<'a, I: 'static> {
    x: &'a I
}

fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    where F: Fn(Lt<'a, I>) -> Lt<'a, I>  // no error, fn bound references 'a
{ unreachable!() }

fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>  //~ERROR explicit lifetimes given
    where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>
{ unreachable!() }

struct X {
    x: u8,
}

impl X {
    fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x }
    //~^ERROR explicit lifetimes given

    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { &self.x } // no error, multiple input refs

    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { }
    //~^ERROR explicit lifetimes given

    fn self_and_same_in<'s>(&'s self, _x: &'s u8) { } // no error, same lifetimes on two params
}

struct Foo<'a>(&'a u8);

impl<'a> Foo<'a> {
    fn self_shared_lifetime(&self, _: &'a u8) {} // no error, lifetime 'a not defined in method
    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} // no error, bounds exist
}

fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
    unimplemented!()
}

fn main() {
}
<commit_msg>Add some tests for lifetime elision lint with types and traits with lifetimes<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#![deny(needless_lifetimes)]
#![allow(dead_code)]
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { }
//~^ERROR explicit lifetimes given

fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { }
//~^ERROR explicit lifetimes given

fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) { } // no error, same lifetime on two params

fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) { } // no error, static involved

fn mut_and_static_input(_x: &mut u8, _y: &'static str) { }

fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x }
//~^ERROR explicit lifetimes given

fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { x } // no error, multiple input refs

fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x } // no error, multiple input refs

fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x } // no error, static involved

fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { Ok(x) } // no error

fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() } // no error, two input refs

fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) }
//~^ERROR explicit lifetimes given

// where clause, but without lifetimes
fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) }
//~^ERROR explicit lifetimes given

type Ref<'r> = &'r u8;

fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } // no error, same lifetime on two params

fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { }
//~^ERROR explicit lifetimes given

fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounded lifetime

fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a { } // no error, bounded lifetime

struct Lt<'a, I: 'static> {
    x: &'a I
}

fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    where F: Fn(Lt<'a, I>) -> Lt<'a, I>  // no error, fn bound references 'a
{ unreachable!() }

fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>  //~ERROR explicit lifetimes given
    where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>
{ unreachable!() }

struct X {
    x: u8,
}

impl X {
    fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x }
    //~^ERROR explicit lifetimes given

    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { &self.x } // no error, multiple input refs

    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { }
    //~^ERROR explicit lifetimes given

    fn self_and_same_in<'s>(&'s self, _x: &'s u8) { } // no error, same lifetimes on two params
}

struct Foo<'a>(&'a u8);

impl<'a> Foo<'a> {
    fn self_shared_lifetime(&self, _: &'a u8) {} // no error, lifetime 'a not defined in method
    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} // no error, bounds exist
}

fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
    unimplemented!()
}

fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { unimplemented!() } //~ERROR explicit lifetimes given

// no warning, two input lifetimes (named on the reference, anonymous on Foo)
fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { unimplemented!() }

// no warning, two input lifetimes (anonymous on the reference, named on Foo)
fn struct_with_lt3<'a>(_foo: &Foo<'a> ) -> &'a str { unimplemented!() }

// no warning, two input lifetimes
fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b> ) -> &'a str { unimplemented!() }

trait WithLifetime<'a> {}
type WithLifetimeAlias<'a> = WithLifetime<'a>;

// should not warn because it won't build without the lifetime
fn trait_obj_elided<'a>(_arg: &'a WithLifetime) -> &'a str { unimplemented!() }

// this should warn because there is no lifetime on Drop, so this would be
// unambiguous if we elided the lifetime
fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { unimplemented!() } //~ERROR explicit lifetimes given

fn main() {
}
<|endoftext|>


<commit_before>use clap::Parser;

#[test]
fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
    #[derive(Parser, Debug, PartialEq)]
    enum Opt {
        Command { foo: u32 },
    }

    assert_eq!(
        Opt::Command { foo: 0 },
        Opt::try_parse_from(&["test", "command", "0"]).unwrap()
    );
}

#[test]
fn test_multi_word_enum_variant_is_renamed() {
    #[derive(Parser, Debug, PartialEq)]
    enum Opt {
        FirstCommand { foo: u32 },
    }

    assert_eq!(
        Opt::FirstCommand { foo: 0 },
        Opt::try_parse_from(&["test", "first-command", "0"]).unwrap()
    );
}

#[test]
fn test_standalone_long_generates_kebab_case() {
    #[derive(Parser, Debug, PartialEq)]
    #[allow(non_snake_case)]
    struct Opt {
        #[clap(long)]
        FOO_OPTION: bool,
    }

    assert_eq!(
        Opt { FOO_OPTION: true },
        Opt::try_parse_from(&["test", "--foo-option"]).unwrap()
    );
}

#[test]
fn test_custom_long_overwrites_default_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(long = "foo")]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foo"]).unwrap()
    );
}

#[test]
fn test_standalone_long_uses_previous_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(name = "foo", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foo"]).unwrap()
    );
}

#[test]
fn test_standalone_long_ignores_afterwards_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(long, name = "foo")]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foo-option"]).unwrap()
    );
}

#[test]
fn test_standalone_short_generates_kebab_case() {
    #[derive(Parser, Debug, PartialEq)]
    #[allow(non_snake_case)]
    struct Opt {
        #[clap(short)]
        FOO_OPTION: bool,
    }

    assert_eq!(
        Opt { FOO_OPTION: true },
        Opt::try_parse_from(&["test", "-f"]).unwrap()
    );
}

#[test]
fn test_custom_short_overwrites_default_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(short = 'o')]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-o"]).unwrap()
    );
}

#[test]
fn test_standalone_short_uses_previous_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(name = "option", short)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-o"]).unwrap()
    );
}

#[test]
fn test_standalone_short_ignores_afterwards_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(short, name = "option")]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-f"]).unwrap()
    );
}

#[test]
fn test_standalone_long_uses_previous_defined_casing() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "screaming_snake", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--FOO_OPTION"]).unwrap()
    );
}

#[test]
fn test_standalone_short_uses_previous_defined_casing() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "screaming_snake", short)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-F"]).unwrap()
    );
}

#[test]
fn test_standalone_long_works_with_verbatim_casing() {
    #[derive(Parser, Debug, PartialEq)]
    #[allow(non_snake_case)]
    struct Opt {
        #[clap(rename_all = "verbatim", long)]
        _fOO_oPtiON: bool,
    }

    assert_eq!(
        Opt { _fOO_oPtiON: true },
        Opt::try_parse_from(&["test", "--_fOO_oPtiON"]).unwrap()
    );
}

#[test]
fn test_standalone_short_works_with_verbatim_casing() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "verbatim", short)]
        _foo: bool,
    }

    assert_eq!(
        Opt { _foo: true },
        Opt::try_parse_from(&["test", "-_"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_propagated_from_struct_to_fields() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    struct Opt {
        #[clap(long)]
        foo: bool,
    }

    assert_eq!(
        Opt { foo: true },
        Opt::try_parse_from(&["test", "--FOO"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_not_propagated_from_struct_into_flattened() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    struct Opt {
        #[clap(flatten)]
        foo: Foo,
    }

    #[derive(Parser, Debug, PartialEq)]
    struct Foo {
        #[clap(long)]
        foo: bool,
    }

    assert_eq!(
        Opt {
            foo: Foo { foo: true }
        },
        Opt::try_parse_from(&["test", "--foo"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_not_propagated_from_struct_into_subcommand() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    struct Opt {
        #[clap(subcommand)]
        foo: Foo,
    }

    #[derive(Parser, Debug, PartialEq)]
    enum Foo {
        Command {
            #[clap(long)]
            foo: bool,
        },
    }

    assert_eq!(
        Opt {
            foo: Foo::Command { foo: true }
        },
        Opt::try_parse_from(&["test", "command", "--foo"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_propagated_from_enum_to_variants_and_their_fields() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    enum Opt {
        FirstVariant,
        SecondVariant {
            #[clap(long)]
            foo: bool,
        },
    }

    assert_eq!(
        Opt::FirstVariant,
        Opt::try_parse_from(&["test", "FIRST_VARIANT"]).unwrap()
    );

    assert_eq!(
        Opt::SecondVariant { foo: true },
        Opt::try_parse_from(&["test", "SECOND_VARIANT", "--FOO"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_propagation_can_be_overridden() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    enum Opt {
        #[clap(rename_all = "kebab_case")]
        FirstVariant {
            #[clap(long)]
            foo_option: bool,
        },
        SecondVariant {
            #[clap(rename_all = "kebab_case", long)]
            foo_option: bool,
        },
    }

    assert_eq!(
        Opt::FirstVariant { foo_option: true },
        Opt::try_parse_from(&["test", "first-variant", "--foo-option"]).unwrap()
    );

    assert_eq!(
        Opt::SecondVariant { foo_option: true },
        Opt::try_parse_from(&["test", "SECOND_VARIANT", "--foo-option"]).unwrap()
    );
}

#[test]
fn test_lower_is_renamed() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "lower", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foooption"]).unwrap()
    );
}

#[test]
fn test_upper_is_renamed() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "upper", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--FOOOPTION"]).unwrap()
    );
}
<commit_msg>refactor(derive): Group subcommand rename tests<commit_after>use clap::Parser;

#[test]
fn test_standalone_long_generates_kebab_case() {
    #[derive(Parser, Debug, PartialEq)]
    #[allow(non_snake_case)]
    struct Opt {
        #[clap(long)]
        FOO_OPTION: bool,
    }

    assert_eq!(
        Opt { FOO_OPTION: true },
        Opt::try_parse_from(&["test", "--foo-option"]).unwrap()
    );
}

#[test]
fn test_custom_long_overwrites_default_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(long = "foo")]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foo"]).unwrap()
    );
}

#[test]
fn test_standalone_long_uses_previous_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(name = "foo", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foo"]).unwrap()
    );
}

#[test]
fn test_standalone_long_ignores_afterwards_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(long, name = "foo")]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foo-option"]).unwrap()
    );
}

#[test]
fn test_standalone_short_generates_kebab_case() {
    #[derive(Parser, Debug, PartialEq)]
    #[allow(non_snake_case)]
    struct Opt {
        #[clap(short)]
        FOO_OPTION: bool,
    }

    assert_eq!(
        Opt { FOO_OPTION: true },
        Opt::try_parse_from(&["test", "-f"]).unwrap()
    );
}

#[test]
fn test_custom_short_overwrites_default_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(short = 'o')]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-o"]).unwrap()
    );
}

#[test]
fn test_standalone_short_uses_previous_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(name = "option", short)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-o"]).unwrap()
    );
}

#[test]
fn test_standalone_short_ignores_afterwards_defined_custom_name() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(short, name = "option")]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-f"]).unwrap()
    );
}

#[test]
fn test_standalone_long_uses_previous_defined_casing() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "screaming_snake", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--FOO_OPTION"]).unwrap()
    );
}

#[test]
fn test_standalone_short_uses_previous_defined_casing() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "screaming_snake", short)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "-F"]).unwrap()
    );
}

#[test]
fn test_standalone_long_works_with_verbatim_casing() {
    #[derive(Parser, Debug, PartialEq)]
    #[allow(non_snake_case)]
    struct Opt {
        #[clap(rename_all = "verbatim", long)]
        _fOO_oPtiON: bool,
    }

    assert_eq!(
        Opt { _fOO_oPtiON: true },
        Opt::try_parse_from(&["test", "--_fOO_oPtiON"]).unwrap()
    );
}

#[test]
fn test_standalone_short_works_with_verbatim_casing() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "verbatim", short)]
        _foo: bool,
    }

    assert_eq!(
        Opt { _foo: true },
        Opt::try_parse_from(&["test", "-_"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_propagated_from_struct_to_fields() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    struct Opt {
        #[clap(long)]
        foo: bool,
    }

    assert_eq!(
        Opt { foo: true },
        Opt::try_parse_from(&["test", "--FOO"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_not_propagated_from_struct_into_flattened() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    struct Opt {
        #[clap(flatten)]
        foo: Foo,
    }

    #[derive(Parser, Debug, PartialEq)]
    struct Foo {
        #[clap(long)]
        foo: bool,
    }

    assert_eq!(
        Opt {
            foo: Foo { foo: true }
        },
        Opt::try_parse_from(&["test", "--foo"]).unwrap()
    );
}

#[test]
fn test_lower_is_renamed() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "lower", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--foooption"]).unwrap()
    );
}

#[test]
fn test_upper_is_renamed() {
    #[derive(Parser, Debug, PartialEq)]
    struct Opt {
        #[clap(rename_all = "upper", long)]
        foo_option: bool,
    }

    assert_eq!(
        Opt { foo_option: true },
        Opt::try_parse_from(&["test", "--FOOOPTION"]).unwrap()
    );
}

#[test]
fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
    #[derive(Parser, Debug, PartialEq)]
    enum Opt {
        Command { foo: u32 },
    }

    assert_eq!(
        Opt::Command { foo: 0 },
        Opt::try_parse_from(&["test", "command", "0"]).unwrap()
    );
}

#[test]
fn test_multi_word_enum_variant_is_renamed() {
    #[derive(Parser, Debug, PartialEq)]
    enum Opt {
        FirstCommand { foo: u32 },
    }

    assert_eq!(
        Opt::FirstCommand { foo: 0 },
        Opt::try_parse_from(&["test", "first-command", "0"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_not_propagated_from_struct_into_subcommand() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    struct Opt {
        #[clap(subcommand)]
        foo: Foo,
    }

    #[derive(Parser, Debug, PartialEq)]
    enum Foo {
        Command {
            #[clap(long)]
            foo: bool,
        },
    }

    assert_eq!(
        Opt {
            foo: Foo::Command { foo: true }
        },
        Opt::try_parse_from(&["test", "command", "--foo"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_propagated_from_enum_to_variants_and_their_fields() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    enum Opt {
        FirstVariant,
        SecondVariant {
            #[clap(long)]
            foo: bool,
        },
    }

    assert_eq!(
        Opt::FirstVariant,
        Opt::try_parse_from(&["test", "FIRST_VARIANT"]).unwrap()
    );

    assert_eq!(
        Opt::SecondVariant { foo: true },
        Opt::try_parse_from(&["test", "SECOND_VARIANT", "--FOO"]).unwrap()
    );
}

#[test]
fn test_rename_all_is_propagation_can_be_overridden() {
    #[derive(Parser, Debug, PartialEq)]
    #[clap(rename_all = "screaming_snake")]
    enum Opt {
        #[clap(rename_all = "kebab_case")]
        FirstVariant {
            #[clap(long)]
            foo_option: bool,
        },
        SecondVariant {
            #[clap(rename_all = "kebab_case", long)]
            foo_option: bool,
        },
    }

    assert_eq!(
        Opt::FirstVariant { foo_option: true },
        Opt::try_parse_from(&["test", "first-variant", "--foo-option"]).unwrap()
    );

    assert_eq!(
        Opt::SecondVariant { foo_option: true },
        Opt::try_parse_from(&["test", "SECOND_VARIANT", "--foo-option"]).unwrap()
    );
}
<|endoftext|>


<commit_before>use raw::{Isolate, Local};

extern "system" {

    #[link_name = "NeonSys_Object_New"]
    pub fn new(out: &mut Local);

    #[link_name = "NeonSys_Object_GetOwnPropertyNames"]
    pub fn get_own_property_names(out: &mut Local, object: Local) -> bool;

    #[link_name = "NeonSys_Object_GetIsolate"]
    pub fn get_isolate(obj: Local) -> *mut Isolate;

    #[link_name = "NeonSys_Object_Get_Index"]
    pub fn get_index(out: &mut Local, object: Local, index: u32) -> bool;

    #[link_name = "NeonSys_Object_Set_Index"]
    pub fn set_index(out: &mut bool, object: Local, index: u32, val: Local) -> bool;

    #[link_name = "NeonSys_Object_Get_String"]
    pub fn get_string(out: &mut Local, object: Local, key: *const u8, len: i32) -> bool;

    #[link_name = "NeonSys_Object_Set_String"]
    pub fn set_string(out: &mut bool, object: Local, key: *const u8, len: i32, val: Local) -> bool;

    #[link_name = "NeonSys_Object_Get"]
    pub fn get(out: &mut Local, object: Local, key: Local) -> bool;

    #[link_name = "NeonSys_Object_Set"]
    pub fn set(out: &mut bool, object: Local, key: Local, val: Local) -> bool;

}
<commit_msg>expand neon_sys::object mod documentation<commit_after>//! Facilities for working with `v8::Object`s.

use raw::{Isolate, Local};

extern "system" {

    /// Mutates the `out` argument provided to refer to a newly created `v8::Object`.
    #[link_name = "NeonSys_Object_New"]
    pub fn new(out: &mut Local);

    /// Mutates the `out` argument provided to refer to a newly created `v8::Array` containing the
    /// names of the `v8::Object`'s own property names. Returns `false` if the result is empty.
    #[link_name = "NeonSys_Object_GetOwnPropertyNames"]
    pub fn get_own_property_names(out: &mut Local, object: Local) -> bool;

    /// Gets the `v8::Isolate` of a `v8::Object`.
    #[link_name = "NeonSys_Object_GetIsolate"]
    pub fn get_isolate(obj: Local) -> *mut Isolate;

    /// Mutates the `out` argument provided to refer to the `v8::Local` value at the `index`
    /// provided of the `v8::Object`. Returns `false` if the result couldn't be retrieved.
    #[link_name = "NeonSys_Object_Get_Index"]
    pub fn get_index(out: &mut Local, object: Local, index: u32) -> bool;

    /// Sets the key value of a `v8::Object` at the `index` provided. Also mutates the `out`
    /// argument provided to refer to a `v8::Local` boolean value, `true` if the set was
    /// successful.
    #[link_name = "NeonSys_Object_Set_Index"]
    pub fn set_index(out: &mut bool, object: Local, index: u32, val: Local) -> bool;

    /// Mutates the `out` argument provided to refer to the `v8::Local` value of the `v8::String`'s
    /// underlying content.  Returns `false` if the value couldn't be retrieved.
    #[link_name = "NeonSys_Object_Get_String"]
    pub fn get_string(out: &mut Local, object: Local, key: *const u8, len: i32) -> bool;

    /// Sets the underlying content of a `v8::String` object. Also mutates the `out` argument
    /// provided to refer to a `v8::Local` boolean value, `true` if the set was successful.
    #[link_name = "NeonSys_Object_Set_String"]
    pub fn set_string(out: &mut bool, object: Local, key: *const u8, len: i32, val: Local) -> bool;

    /// Mutates the `out` argument provided to refer to the `v8::Local` value at the `key`
    /// provided. Returns `false` if the result couldn't be retrieved.
    #[link_name = "NeonSys_Object_Get"]
    pub fn get(out: &mut Local, object: Local, key: Local) -> bool;

    /// Sets the key value of a `v8::Object` at the `key` provided. Also mutates the `out` argument
    /// provided to refer to a `v8::Local` boolean value, `true` if the set was successful.
    #[link_name = "NeonSys_Object_Set"]
    pub fn set(out: &mut bool, object: Local, key: Local, val: Local) -> bool;

}
<|endoftext|>


<commit_before>fn main() {
    // basic arithmetic
    assert_eq!(6.0_f32*6.0_f32, 36.0_f32);
    assert_eq!(6.0_f64*6.0_f64, 36.0_f64);
    assert_eq!(-{5.0_f32}, -5.0_f32);
    assert_eq!(-{5.0_f64}, -5.0_f64);
    // infinities, NaN
    assert!((5.0_f32/0.0).is_infinite());
    assert!((5.0_f64/0.0).is_infinite());
    assert!((-5.0_f32).sqrt().is_nan());
    assert!((-5.0_f64).sqrt().is_nan());
    // byte-level transmute
    let x: u64 = unsafe { std::mem::transmute(42.0_f64) };
    let y: f64 = unsafe { std::mem::transmute(x) };
    assert_eq!(y, 42.0_f64);
    let x: u32 = unsafe { std::mem::transmute(42.0_f32) };
    let y: f32 = unsafe { std::mem::transmute(x) };
    assert_eq!(y, 42.0_f32);

    // f32 casts
    assert_eq!(5.0f32 as u32, 5);
    assert_eq!(-5.0f32 as u32, 0);
    assert_eq!(5.0f32 as i32, 5);
    assert_eq!(-5.0f32 as i32, -5);
    assert_eq!(std::f32::MAX as i32, i32::MAX);
    assert_eq!(std::f32::INFINITY as i32, i32::MAX);
    assert_eq!(std::f32::MAX as u32, u32::MAX);
    assert_eq!(std::f32::INFINITY as u32, u32::MAX);
    assert_eq!(std::f32::MIN as i32, i32::MIN);
    assert_eq!(std::f32::NEG_INFINITY as i32, i32::MIN);
    assert_eq!(std::f32::MIN as u32, 0);
    assert_eq!(std::f32::NEG_INFINITY as u32, 0);
    assert_eq!(std::f32::NAN as i32, 0);
    assert_eq!(std::f32::NAN as u32, 0);
    assert_eq!(u128::MAX as f32, std::f32::INFINITY);
    assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss
    assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss

    // f64 casts
    assert_eq!(5.0f64 as u64, 5);
    assert_eq!(-5.0f64 as u64, 0);
    assert_eq!(5.0f64 as i64, 5);
    assert_eq!(-5.0f64 as i64, -5);
    assert_eq!(std::f64::MAX as i64, i64::MAX);
    assert_eq!(std::f64::INFINITY as i64, i64::MAX);
    assert_eq!(std::f64::MAX as u64, u64::MAX);
    assert_eq!(std::f64::INFINITY as u64, u64::MAX);
    assert_eq!(std::f64::MIN as i64, i64::MIN);
    assert_eq!(std::f64::NEG_INFINITY as i64, i64::MIN);
    assert_eq!(std::f64::MIN as u64, 0);
    assert_eq!(std::f64::NEG_INFINITY as u64, 0);
    assert_eq!(std::f64::NAN as i64, 0);
    assert_eq!(std::f64::NAN as u64, 0);
    assert_eq!(u128::MAX as f64 as u128, u128::MAX);
    assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss
    assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss

    // f32 min/max
    assert_eq!((1.0 as f32).max(-1.0), 1.0);
    assert_eq!((1.0 as f32).min(-1.0), -1.0);
    assert_eq!(std::f32::NAN.min(9.0), 9.0);
    assert_eq!(std::f32::NAN.max(-9.0), -9.0);
    assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0);
    assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0);

    // f64 min/max
    assert_eq!((1.0 as f64).max(-1.0), 1.0);
    assert_eq!((1.0 as f64).min(-1.0), -1.0);
    assert_eq!(std::f64::NAN.min(9.0), 9.0);
    assert_eq!(std::f64::NAN.max(-9.0), -9.0);
    assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0);
    assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0);

    // f32 copysign
    assert_eq!(3.5_f32.copysign(0.42), 3.5_f32);
    assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32);
    assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32);
    assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32);
    assert!(std::f32::NAN.copysign(1.0).is_nan());

    // f64 copysign
    assert_eq!(3.5_f64.copysign(0.42), 3.5_f64);
    assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64);
    assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64);
    assert_eq!((-3.5_f64).copysign(-0.42), -3.5_f64);
    assert!(std::f64::NAN.copysign(1.0).is_nan());
}
<commit_msg>also do some float-to-float cast testing<commit_after>fn main() {
    // basic arithmetic
    assert_eq!(6.0_f32*6.0_f32, 36.0_f32);
    assert_eq!(6.0_f64*6.0_f64, 36.0_f64);
    assert_eq!(-{5.0_f32}, -5.0_f32);
    assert_eq!(-{5.0_f64}, -5.0_f64);
    // infinities, NaN
    assert!((5.0_f32/0.0).is_infinite());
    assert!((5.0_f64/0.0).is_infinite());
    assert!((-5.0_f32).sqrt().is_nan());
    assert!((-5.0_f64).sqrt().is_nan());
    // byte-level transmute
    let x: u64 = unsafe { std::mem::transmute(42.0_f64) };
    let y: f64 = unsafe { std::mem::transmute(x) };
    assert_eq!(y, 42.0_f64);
    let x: u32 = unsafe { std::mem::transmute(42.0_f32) };
    let y: f32 = unsafe { std::mem::transmute(x) };
    assert_eq!(y, 42.0_f32);

    // f32-to-int casts
    assert_eq!(5.0f32 as u32, 5);
    assert_eq!(-5.0f32 as u32, 0);
    assert_eq!(5.0f32 as i32, 5);
    assert_eq!(-5.0f32 as i32, -5);
    assert_eq!(std::f32::MAX as i32, i32::MAX);
    assert_eq!(std::f32::INFINITY as i32, i32::MAX);
    assert_eq!(std::f32::MAX as u32, u32::MAX);
    assert_eq!(std::f32::INFINITY as u32, u32::MAX);
    assert_eq!(std::f32::MIN as i32, i32::MIN);
    assert_eq!(std::f32::NEG_INFINITY as i32, i32::MIN);
    assert_eq!(std::f32::MIN as u32, 0);
    assert_eq!(std::f32::NEG_INFINITY as u32, 0);
    assert_eq!(std::f32::NAN as i32, 0);
    assert_eq!(std::f32::NAN as u32, 0);
    assert_eq!(u128::MAX as f32, std::f32::INFINITY);
    assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss
    assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss

    // f64-to-int casts
    assert_eq!(5.0f64 as u64, 5);
    assert_eq!(-5.0f64 as u64, 0);
    assert_eq!(5.0f64 as i64, 5);
    assert_eq!(-5.0f64 as i64, -5);
    assert_eq!(std::f64::MAX as i64, i64::MAX);
    assert_eq!(std::f64::INFINITY as i64, i64::MAX);
    assert_eq!(std::f64::MAX as u64, u64::MAX);
    assert_eq!(std::f64::INFINITY as u64, u64::MAX);
    assert_eq!(std::f64::MIN as i64, i64::MIN);
    assert_eq!(std::f64::NEG_INFINITY as i64, i64::MIN);
    assert_eq!(std::f64::MIN as u64, 0);
    assert_eq!(std::f64::NEG_INFINITY as u64, 0);
    assert_eq!(std::f64::NAN as i64, 0);
    assert_eq!(std::f64::NAN as u64, 0);
    assert_eq!(u128::MAX as f64 as u128, u128::MAX);
    assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss
    assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss

    // f32 <-> f64 casts
    assert_eq!(5.0f64 as f32, 5.0f32);
    assert_eq!(5.0f32 as f64, 5.0f64);
    assert_eq!(std::f64::MAX as f32, std::f32::INFINITY);
    assert_eq!(std::f64::MIN as f32, std::f32::NEG_INFINITY);
    assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY);
    assert_eq!(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY);

    // f32 min/max
    assert_eq!((1.0 as f32).max(-1.0), 1.0);
    assert_eq!((1.0 as f32).min(-1.0), -1.0);
    assert_eq!(std::f32::NAN.min(9.0), 9.0);
    assert_eq!(std::f32::NAN.max(-9.0), -9.0);
    assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0);
    assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0);

    // f64 min/max
    assert_eq!((1.0 as f64).max(-1.0), 1.0);
    assert_eq!((1.0 as f64).min(-1.0), -1.0);
    assert_eq!(std::f64::NAN.min(9.0), 9.0);
    assert_eq!(std::f64::NAN.max(-9.0), -9.0);
    assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0);
    assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0);

    // f32 copysign
    assert_eq!(3.5_f32.copysign(0.42), 3.5_f32);
    assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32);
    assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32);
    assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32);
    assert!(std::f32::NAN.copysign(1.0).is_nan());

    // f64 copysign
    assert_eq!(3.5_f64.copysign(0.42), 3.5_f64);
    assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64);
    assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64);
    assert_eq!((-3.5_f64).copysign(-0.42), -3.5_f64);
    assert!(std::f64::NAN.copysign(1.0).is_nan());
}
<|endoftext|>


<commit_before>use buckets::Buckets;
use time;
use std::net::TcpStream;
use std::io::{BufReader, BufRead, Write};
use std::fmt::Write as fmtWrite;

/// Handle the management commands
/// returning the response to send back.
pub fn exec(stream: TcpStream, buckets: &mut Buckets) {
    let mut reader = BufReader::new(stream);
    let mut done = false;

    while !done {
        let mut buffer = String::new();
        let _ = reader.read_line(&mut buffer);
        let command = buffer.split_whitespace()
            .next()
            .unwrap_or("")
            .to_lowercase();
        let mut writer = reader.get_mut();
        let mut out = String::new();

        // Trigger Deref<Target = str>
        match &*command {
            "help" => {
                out.push_str("Statsd Admin Console:\n");
                out.push_str("\n");
                out.push_str("Available commands:\n");
                out.push_str("stats    - print server stats.\n");
                out.push_str("counters - print counter data.\n");
                out.push_str("gauges   - print gauge data.\n");
                out.push_str("timers   - print timer data.\n");
                out.push_str("clear    - clear stored metrics.\n");
                out.push_str("quit     - close this connection.\n");
            },
            "stats" => {
                let uptime = (time::get_time() - buckets.start_time()).num_seconds();
                write!(out, "uptime: {} seconds\n", uptime).unwrap();
                write!(out, "bad_messages: {}\n", buckets.bad_messages()).unwrap();
                write!(out, "total_messages: {}\n", buckets.total_messages()).unwrap();
                write!(out, "END\n\n").unwrap();
            },
            "counters" => {
                for (key, value) in buckets.counters().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "gauges" => {
                for (key, value) in buckets.gauges().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "timers" => {
                for (key, value) in buckets.timers().iter() {
                    write!(out, " {}: {:?}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "quit" => {
                write!(out, "Good bye!\n\n").unwrap();
                done = true
            },
            "clear" => {
                buckets.reset();
                write!(out, "Timers, counters and internal stats cleared.\n").unwrap();
            },
            x => {
                write!(out, "ERROR - unknown command `{}`\n", x).unwrap();
            }
        }
        let _ = writer.write(&out.as_bytes());
        let _ = writer.flush();
    }
}
<commit_msg>Don't write output when there is no content.<commit_after>use buckets::Buckets;
use time;
use std::net::TcpStream;
use std::io::{BufReader, BufRead, Write};
use std::fmt::Write as fmtWrite;

/// Handle the management commands
/// returning the response to send back.
pub fn exec(stream: TcpStream, buckets: &mut Buckets) {
    let mut reader = BufReader::new(stream);
    let mut done = false;

    while !done {
        let mut buffer = String::new();
        let _ = reader.read_line(&mut buffer);
        let command = buffer.split_whitespace()
            .next()
            .unwrap_or("")
            .to_lowercase();
        let mut writer = reader.get_mut();
        let mut out = String::new();

        // Trigger Deref<Target = str>
        match &*command {
            "help" => {
                out.push_str("Statsd Admin Console:\n");
                out.push_str("\n");
                out.push_str("Available commands:\n");
                out.push_str("stats    - print server stats.\n");
                out.push_str("counters - print counter data.\n");
                out.push_str("gauges   - print gauge data.\n");
                out.push_str("timers   - print timer data.\n");
                out.push_str("clear    - clear stored metrics.\n");
                out.push_str("quit     - close this connection.\n");
            },
            "stats" => {
                let uptime = (time::get_time() - buckets.start_time()).num_seconds();
                write!(out, "uptime: {} seconds\n", uptime).unwrap();
                write!(out, "bad_messages: {}\n", buckets.bad_messages()).unwrap();
                write!(out, "total_messages: {}\n", buckets.total_messages()).unwrap();
                write!(out, "END\n\n").unwrap();
            },
            "counters" => {
                for (key, value) in buckets.counters().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "gauges" => {
                for (key, value) in buckets.gauges().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "timers" => {
                for (key, value) in buckets.timers().iter() {
                    write!(out, " {}: {:?}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "quit" => {
                write!(out, "Good bye!\n\n").unwrap();
                done = true
            },
            "clear" => {
                buckets.reset();
                write!(out, "Timers, counters and internal stats cleared.\n").unwrap();
            },
            "" => {
                // continue.
            },
            x => {
                write!(out, "ERROR - unknown command `{}`\n", x).unwrap();
            }
        }
        if out.len() > 0 {
            let _ = writer.write(&out.as_bytes());
            let _ = writer.flush();
        }
    }
}
<|endoftext|>