<commit_before>//! Main interface for a stream of events the Supervisor can send out
//! in the course of its operations.
//!
//! Currently, the Supervisor is able to send events to a [NATS
//! Streaming][1] server. The `init_stream` function must be called
//! before sending events to initialize the publishing thread in the
//! background. Thereafter, you can pass "event" structs to the
//! `event` function, which will publish the event to the stream.
//!
//! All events are published under the "habitat" subject.
//!
//! [1]:https://github.com/nats-io/nats-streaming-server

mod error;

#[cfg(feature = "nitox_stream")]
#[path = "event/nitox.rs"]
mod stream_impl;

// This is the default, but setting it as a default in Cargo.toml
// makes it trickier to use nitox instead.
#[cfg(any(feature = "ratsio_stream", not(feature = "nitox_stream")))]
#[path = "event/ratsio.rs"]
mod stream_impl;
mod types;

pub(crate) use self::types::ServiceMetadata;
use self::types::{EventMessage,
                  EventMetadata,
                  HealthCheckEvent,
                  ServiceStartedEvent,
                  ServiceStoppedEvent};
use crate::{error::Result as SupResult,
            manager::{service::{HealthCheckResult,
                                Service},
                      sys::Sys}};
use clap::ArgMatches;
pub use error::{Error,
                Result};
use futures::sync::mpsc::UnboundedSender;
use habitat_common::types::{AutomateAuthToken,
                            EventStreamMetadata};
use habitat_core::env::Config as EnvConfig;
use state::Container;
use std::{net::SocketAddr,
          num::ParseIntError,
          str::FromStr,
          sync::Once,
          time::Duration};

static INIT: Once = Once::new();
lazy_static! {
    // TODO (CM): When const fn support lands in stable, we can ditch
    // this lazy_static call.

    /// Reference to the event stream.
    static ref EVENT_STREAM: Container = Container::new();
    /// Core information that is shared between all events.
    static ref EVENT_CORE: Container = Container::new();
}

/// Starts a new thread for sending events to a NATS Streaming
/// server. Stashes the handle to the stream, as well as the core
/// event information that will be a part of all events, in a global
/// static reference for access later.
pub fn init_stream(config: EventStreamConfig, event_core: EventCore) -> Result<()> {
    // call_once can't return a Result (or anything), so we'll fake it
    // by hanging onto any error here.
    let mut init_err: Option<Error> = None;

    INIT.call_once(|| {
            let conn_info = EventConnectionInfo::new(config.token, config.url);
            match stream_impl::init_stream(conn_info) {
                Ok(event_stream) => {
                    EVENT_STREAM.set(event_stream);
                    EVENT_CORE.set(event_core);
                }
                Err(e) => init_err = Some(e),
            }
        });

    if let Some(err) = init_err {
        Err(err)
    } else {
        Ok(())
    }
}

/// Captures all event stream-related configuration options that would
/// be passed in by a user
#[derive(Clone, Debug)]
pub struct EventStreamConfig {
    environment: String,
    application: String,
    meta:        EventStreamMetadata,
    token:       AutomateAuthToken,
    url:         String,
}

impl EventStreamConfig {
    /// Create an instance from Clap arguments.
    // TODO (CM): result type!
    pub fn from_matches(m: &ArgMatches) -> SupResult<EventStreamConfig> {
        Ok(EventStreamConfig { environment: m.value_of("EVENT_STREAM_ENVIRONMENT")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               application: m.value_of("EVENT_STREAM_APPLICATION")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               meta:        EventStreamMetadata::from(m),
                               token:       AutomateAuthToken::from(m),
                               url:         m.value_of("EVENT_STREAM_URL")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"), })
    }
}

/// All the information needed to establish a connection to a NATS
/// Streaming server.
// TODO: This will change as we firm up what the interaction between
// Habitat and A2 looks like.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
    pub auth_token:  AutomateAuthToken,
}

impl EventConnectionInfo {
    pub fn new(auth_token: AutomateAuthToken, cluster_uri: String) -> Self {
        EventConnectionInfo { name: String::from("hab_client"),
                              verbose: true,
                              cluster_uri,
                              cluster_id: String::from("event-service"),
                              auth_token }
    }
}

/// A collection of data that will be present in all events. Rather
/// than baking this into the structure of each event, we represent it
/// once and merge the information into the final rendered form of the
/// event.
///
/// This prevents us from having to thread information throughout the
/// system, just to get it to the places where the events are
/// generated (e.g., not all code has direct access to the
/// Supervisor's ID).
#[derive(Clone, Debug)]
pub struct EventCore {
    /// The unique identifier of the Supervisor sending the event.
    supervisor_id: String,
    ip_address: SocketAddr,
    // TODO (CM): could add application and environment to the meta
    // map directly... hrmm
    application: String,
    environment: String,
    meta:        EventStreamMetadata,
}

impl EventCore {
    pub fn new(config: &EventStreamConfig, sys: &Sys) -> Self {
        EventCore { supervisor_id: sys.member_id.clone(),
                    ip_address:    sys.gossip_listen(),
                    environment:   config.environment.clone(),
                    application:   config.application.clone(),
                    meta:          config.meta.clone(), }
    }
}

/// Send an event for the start of a Service.
pub fn service_started(service: &Service) {
    if stream_initialized() {
        publish(ServiceStartedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

/// Send an event for the stop of a Service.
pub fn service_stopped(service: &Service) {
    if stream_initialized() {
        publish(ServiceStoppedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

// Takes metadata directly, rather than a `&Service` like other event
// functions, because of how the asynchronous health checking
// currently works. Revisit when async/await + Pin is all stabilized.
pub fn health_check(metadata: ServiceMetadata,
                    check_result: HealthCheckResult,
                    duration: Option<Duration>) {
    if stream_initialized() {
        publish(HealthCheckEvent { service_metadata: Some(metadata),
                                   event_metadata:   None,
                                   result:           Into::<types::HealthCheck>::into(check_result)
                                                     as i32,
                                   duration:         duration.map(Duration::into), });
    }
}

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

/// Internal helper function to know whether or not to go to the trouble of
/// creating event structures. If the event stream hasn't been
/// initialized, then we shouldn't need to do anything.
fn stream_initialized() -> bool { EVENT_STREAM.try_get::<EventStream>().is_some() }

/// Publish an event. This is the main interface that client code will
/// use.
///
/// If `init_stream` has not been called already, this function will
/// be a no-op.
fn publish(mut event: impl EventMessage) {
    if let Some(e) = EVENT_STREAM.try_get::<EventStream>() {
        // TODO (CM): Yeah... this is looking pretty gross. The
        // intention is to be able to timestamp the events right as
        // they go out.
        //
        // We *could* set the time when we convert the EventCore to a
        // EventMetadata struct, but that seems odd.
        //
        // It probably means that this structure just isn't the right
        // one.
        //
        // The ugliness is at least contained, though.
        event.event_metadata(EventMetadata { timestamp:
                                                 Some(std::time::SystemTime::now().into()),
                                             ..EVENT_CORE.get::<EventCore>().to_event_metadata() });

        e.send(event.to_bytes());
    }
}

/// A lightweight handle for the event stream. All events get to the
/// event stream through this.
struct EventStream(UnboundedSender<Vec<u8>>);

impl EventStream {
    /// Queues an event to be sent out.
    fn send(&self, event: Vec<u8>) {
        trace!("About to queue an event: {:?}", event);
        if let Err(e) = self.0.unbounded_send(event) {
            error!("Failed to queue event: {:?}", e);
        }
    }
}

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

/// How long should we for the event thread to start up before
/// abandoning it and shutting down?
#[derive(Clone, Debug)]
struct EventThreadStartupWait(u64);

impl Default for EventThreadStartupWait {
    fn default() -> Self { Self(5) }
}

impl FromStr for EventThreadStartupWait {
    type Err = ParseIntError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { Ok(Self(s.parse()?)) }
}

impl EnvConfig for EventThreadStartupWait {
    const ENVVAR: &'static str = "HAB_EVENT_THREAD_STARTUP_WAIT_SEC";
}

impl Into<Duration> for EventThreadStartupWait {
    fn into(self) -> Duration { Duration::from_secs(self.0) }
}
<commit_msg>[PR Feedback] Simplify init_stream by using Result, not Option<commit_after>//! Main interface for a stream of events the Supervisor can send out
//! in the course of its operations.
//!
//! Currently, the Supervisor is able to send events to a [NATS
//! Streaming][1] server. The `init_stream` function must be called
//! before sending events to initialize the publishing thread in the
//! background. Thereafter, you can pass "event" structs to the
//! `event` function, which will publish the event to the stream.
//!
//! All events are published under the "habitat" subject.
//!
//! [1]:https://github.com/nats-io/nats-streaming-server

mod error;

#[cfg(feature = "nitox_stream")]
#[path = "event/nitox.rs"]
mod stream_impl;

// This is the default, but setting it as a default in Cargo.toml
// makes it trickier to use nitox instead.
#[cfg(any(feature = "ratsio_stream", not(feature = "nitox_stream")))]
#[path = "event/ratsio.rs"]
mod stream_impl;
mod types;

pub(crate) use self::types::ServiceMetadata;
use self::types::{EventMessage,
                  EventMetadata,
                  HealthCheckEvent,
                  ServiceStartedEvent,
                  ServiceStoppedEvent};
use crate::{error::Result as SupResult,
            manager::{service::{HealthCheckResult,
                                Service},
                      sys::Sys}};
use clap::ArgMatches;
pub use error::{Error,
                Result};
use futures::sync::mpsc::UnboundedSender;
use habitat_common::types::{AutomateAuthToken,
                            EventStreamMetadata};
use habitat_core::env::Config as EnvConfig;
use state::Container;
use std::{net::SocketAddr,
          num::ParseIntError,
          str::FromStr,
          sync::Once,
          time::Duration};

static INIT: Once = Once::new();
lazy_static! {
    // TODO (CM): When const fn support lands in stable, we can ditch
    // this lazy_static call.

    /// Reference to the event stream.
    static ref EVENT_STREAM: Container = Container::new();
    /// Core information that is shared between all events.
    static ref EVENT_CORE: Container = Container::new();
}

/// Starts a new thread for sending events to a NATS Streaming
/// server. Stashes the handle to the stream, as well as the core
/// event information that will be a part of all events, in a global
/// static reference for access later.
pub fn init_stream(config: EventStreamConfig, event_core: EventCore) -> Result<()> {
    // call_once can't return a Result (or anything), so we'll fake it
    // by hanging onto any error we might receive.
    let mut return_value: Result<()> = Ok(());

    INIT.call_once(|| {
            let conn_info = EventConnectionInfo::new(config.token, config.url);
            match stream_impl::init_stream(conn_info) {
                Ok(event_stream) => {
                    EVENT_STREAM.set(event_stream);
                    EVENT_CORE.set(event_core);
                }
                Err(e) => return_value = Err(e),
            }
        });

    return_value
}

/// Captures all event stream-related configuration options that would
/// be passed in by a user
#[derive(Clone, Debug)]
pub struct EventStreamConfig {
    environment: String,
    application: String,
    meta:        EventStreamMetadata,
    token:       AutomateAuthToken,
    url:         String,
}

impl EventStreamConfig {
    /// Create an instance from Clap arguments.
    // TODO (CM): result type!
    pub fn from_matches(m: &ArgMatches) -> SupResult<EventStreamConfig> {
        Ok(EventStreamConfig { environment: m.value_of("EVENT_STREAM_ENVIRONMENT")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               application: m.value_of("EVENT_STREAM_APPLICATION")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               meta:        EventStreamMetadata::from(m),
                               token:       AutomateAuthToken::from(m),
                               url:         m.value_of("EVENT_STREAM_URL")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"), })
    }
}

/// All the information needed to establish a connection to a NATS
/// Streaming server.
// TODO: This will change as we firm up what the interaction between
// Habitat and A2 looks like.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
    pub auth_token:  AutomateAuthToken,
}

impl EventConnectionInfo {
    pub fn new(auth_token: AutomateAuthToken, cluster_uri: String) -> Self {
        EventConnectionInfo { name: String::from("hab_client"),
                              verbose: true,
                              cluster_uri,
                              cluster_id: String::from("event-service"),
                              auth_token }
    }
}

/// A collection of data that will be present in all events. Rather
/// than baking this into the structure of each event, we represent it
/// once and merge the information into the final rendered form of the
/// event.
///
/// This prevents us from having to thread information throughout the
/// system, just to get it to the places where the events are
/// generated (e.g., not all code has direct access to the
/// Supervisor's ID).
#[derive(Clone, Debug)]
pub struct EventCore {
    /// The unique identifier of the Supervisor sending the event.
    supervisor_id: String,
    ip_address: SocketAddr,
    // TODO (CM): could add application and environment to the meta
    // map directly... hrmm
    application: String,
    environment: String,
    meta:        EventStreamMetadata,
}

impl EventCore {
    pub fn new(config: &EventStreamConfig, sys: &Sys) -> Self {
        EventCore { supervisor_id: sys.member_id.clone(),
                    ip_address:    sys.gossip_listen(),
                    environment:   config.environment.clone(),
                    application:   config.application.clone(),
                    meta:          config.meta.clone(), }
    }
}

/// Send an event for the start of a Service.
pub fn service_started(service: &Service) {
    if stream_initialized() {
        publish(ServiceStartedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

/// Send an event for the stop of a Service.
pub fn service_stopped(service: &Service) {
    if stream_initialized() {
        publish(ServiceStoppedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

// Takes metadata directly, rather than a `&Service` like other event
// functions, because of how the asynchronous health checking
// currently works. Revisit when async/await + Pin is all stabilized.
pub fn health_check(metadata: ServiceMetadata,
                    check_result: HealthCheckResult,
                    duration: Option<Duration>) {
    if stream_initialized() {
        publish(HealthCheckEvent { service_metadata: Some(metadata),
                                   event_metadata:   None,
                                   result:           Into::<types::HealthCheck>::into(check_result)
                                                     as i32,
                                   duration:         duration.map(Duration::into), });
    }
}

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

/// Internal helper function to know whether or not to go to the trouble of
/// creating event structures. If the event stream hasn't been
/// initialized, then we shouldn't need to do anything.
fn stream_initialized() -> bool { EVENT_STREAM.try_get::<EventStream>().is_some() }

/// Publish an event. This is the main interface that client code will
/// use.
///
/// If `init_stream` has not been called already, this function will
/// be a no-op.
fn publish(mut event: impl EventMessage) {
    if let Some(e) = EVENT_STREAM.try_get::<EventStream>() {
        // TODO (CM): Yeah... this is looking pretty gross. The
        // intention is to be able to timestamp the events right as
        // they go out.
        //
        // We *could* set the time when we convert the EventCore to a
        // EventMetadata struct, but that seems odd.
        //
        // It probably means that this structure just isn't the right
        // one.
        //
        // The ugliness is at least contained, though.
        event.event_metadata(EventMetadata { timestamp:
                                                 Some(std::time::SystemTime::now().into()),
                                             ..EVENT_CORE.get::<EventCore>().to_event_metadata() });

        e.send(event.to_bytes());
    }
}

/// A lightweight handle for the event stream. All events get to the
/// event stream through this.
struct EventStream(UnboundedSender<Vec<u8>>);

impl EventStream {
    /// Queues an event to be sent out.
    fn send(&self, event: Vec<u8>) {
        trace!("About to queue an event: {:?}", event);
        if let Err(e) = self.0.unbounded_send(event) {
            error!("Failed to queue event: {:?}", e);
        }
    }
}

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

/// How long should we for the event thread to start up before
/// abandoning it and shutting down?
#[derive(Clone, Debug)]
struct EventThreadStartupWait(u64);

impl Default for EventThreadStartupWait {
    fn default() -> Self { Self(5) }
}

impl FromStr for EventThreadStartupWait {
    type Err = ParseIntError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { Ok(Self(s.parse()?)) }
}

impl EnvConfig for EventThreadStartupWait {
    const ENVVAR: &'static str = "HAB_EVENT_THREAD_STARTUP_WAIT_SEC";
}

impl Into<Duration> for EventThreadStartupWait {
    fn into(self) -> Duration { Duration::from_secs(self.0) }
}
<|endoftext|>


<commit_before>//! Main interface for a stream of events the Supervisor can send out
//! in the course of its operations.
//!
//! Currently, the Supervisor is able to send events to a [NATS
//! Streaming][1] server. The `init_stream` function must be called
//! before sending events to initialize the publishing thread in the
//! background. Thereafter, you can pass "event" structs to the
//! `event` function, which will publish the event to the stream.
//!
//! All events are published under the "habitat" subject.
//!
//! [1]:https://github.com/nats-io/nats-streaming-server

mod error;
// ratsio_stream is the default, but setting it as a default in Cargo.toml
// makes it trickier to use nitox instead.
#[cfg(feature = "nitox_stream")]
#[path = "event/nitox.rs"]
mod stream_impl;
#[cfg(any(feature = "ratsio_stream", not(feature = "nitox_stream")))]
#[path = "event/ratsio.rs"]
mod stream_impl;
mod types;

pub(crate) use self::types::ServiceMetadata;
use self::types::{EventMessage,
                  EventMetadata,
                  HealthCheckEvent,
                  ServiceStartedEvent,
                  ServiceStoppedEvent};
use crate::manager::{service::{HealthCheckResult,
                               Service},
                     sys::Sys};
use clap::ArgMatches;
pub use error::{Error,
                Result};
use futures::sync::mpsc::UnboundedSender;
use habitat_common::types::{AutomateAuthToken,
                            EventStreamMetadata};
use habitat_core::env::Config as EnvConfig;
use state::Container;
use std::{net::SocketAddr,
          num::ParseIntError,
          str::FromStr,
          sync::Once,
          time::Duration};

static INIT: Once = Once::new();
lazy_static! {
    // TODO (CM): When const fn support lands in stable, we can ditch
    // this lazy_static call.

    /// Reference to the event stream.
    static ref EVENT_STREAM: Container = Container::new();
    /// Core information that is shared between all events.
    static ref EVENT_CORE: Container = Container::new();
}

/// Starts a new thread for sending events to a NATS Streaming
/// server. Stashes the handle to the stream, as well as the core
/// event information that will be a part of all events, in a global
/// static reference for access later.
pub fn init_stream(config: EventStreamConfig, event_core: EventCore) -> Result<()> {
    // call_once can't return a Result (or anything), so we'll fake it
    // by hanging onto any error we might receive.
    let mut return_value: Result<()> = Ok(());

    INIT.call_once(|| {
            let conn_info = EventConnectionInfo::new(config.token, config.url);
            match stream_impl::init_stream(conn_info) {
                Ok(event_stream) => {
                    EVENT_STREAM.set(event_stream);
                    EVENT_CORE.set(event_core);
                }
                Err(e) => return_value = Err(e),
            }
        });

    return_value
}

/// Captures all event stream-related configuration options that would
/// be passed in by a user
#[derive(Clone, Debug)]
pub struct EventStreamConfig {
    environment: String,
    application: String,
    site:        Option<String>,
    meta:        EventStreamMetadata,
    token:       AutomateAuthToken,
    url:         String,
}

impl<'a> From<&'a ArgMatches<'a>> for EventStreamConfig {
    fn from(m: &ArgMatches) -> Self {
        EventStreamConfig { environment: m.value_of("EVENT_STREAM_ENVIRONMENT")
                                          .map(str::to_string)
                                          .expect("Required option for EventStream feature"),
                            application: m.value_of("EVENT_STREAM_APPLICATION")
                                          .map(str::to_string)
                                          .expect("Required option for EventStream feature"),
                            site:        m.value_of("EVENT_STREAM_SITE").map(str::to_string),
                            meta:        EventStreamMetadata::from(m),
                            token:       AutomateAuthToken::from(m),
                            url:         m.value_of("EVENT_STREAM_URL")
                                          .map(str::to_string)
                                          .expect("Required option for EventStream feature"), }
    }
}

/// All the information needed to establish a connection to a NATS
/// Streaming server.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
    pub auth_token:  AutomateAuthToken,
}

impl EventConnectionInfo {
    pub fn new(auth_token: AutomateAuthToken, cluster_uri: String) -> Self {
        EventConnectionInfo { name: "hab_client".to_string(),
                              verbose: true,
                              cluster_uri,
                              cluster_id: "event-service".to_string(),
                              auth_token }
    }
}

/// A collection of data that will be present in all events. Rather
/// than baking this into the structure of each event, we represent it
/// once and merge the information into the final rendered form of the
/// event.
///
/// This prevents us from having to thread information throughout the
/// system, just to get it to the places where the events are
/// generated (e.g., not all code has direct access to the
/// Supervisor's ID).
#[derive(Clone, Debug)]
pub struct EventCore {
    /// The unique identifier of the Supervisor sending the event.
    supervisor_id: String,
    ip_address: SocketAddr,
    fqdn: String,
    application: String,
    environment: String,
    site: Option<String>,
    meta: EventStreamMetadata,
}

impl EventCore {
    pub fn new(config: &EventStreamConfig, sys: &Sys, fqdn: String) -> Self {
        EventCore { supervisor_id: sys.member_id.clone(),
                    ip_address: sys.gossip_listen(),
                    fqdn,
                    environment: config.environment.clone(),
                    application: config.application.clone(),
                    site: config.site.clone(),
                    meta: config.meta.clone() }
    }
}

/// Send an event for the start of a Service.
pub fn service_started(service: &Service) {
    if stream_initialized() {
        publish(ServiceStartedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

/// Send an event for the stop of a Service.
pub fn service_stopped(service: &Service) {
    if stream_initialized() {
        publish(ServiceStoppedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

// Takes metadata directly, rather than a `&Service` like other event
// functions, because of how the asynchronous health checking
// currently works. Revisit when async/await + Pin is all stabilized.
/// `execution` will be `Some` if the service had a hook to run, and
/// records how long it took that hook to execute completely.
pub fn health_check(metadata: ServiceMetadata,
                    check_result: HealthCheckResult,
                    execution: Option<Duration>) {
    if stream_initialized() {
        let check_result: types::HealthCheckResult = check_result.into();
        publish(HealthCheckEvent { service_metadata: Some(metadata),
                                   event_metadata:   None,
                                   result:           i32::from(check_result),
                                   execution:        execution.map(Duration::into), });
    }
}

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

/// Internal helper function to know whether or not to go to the trouble of
/// creating event structures. If the event stream hasn't been
/// initialized, then we shouldn't need to do anything.
fn stream_initialized() -> bool { EVENT_STREAM.try_get::<EventStream>().is_some() }

/// Publish an event. This is the main interface that client code will
/// use.
///
/// If `init_stream` has not been called already, this function will
/// be a no-op.
fn publish(mut event: impl EventMessage) {
    if let Some(e) = EVENT_STREAM.try_get::<EventStream>() {
        // TODO (CM): Yeah... this is looking pretty gross. The
        // intention is to be able to timestamp the events right as
        // they go out.
        //
        // We *could* set the time when we convert the EventCore to a
        // EventMetadata struct, but that seems odd.
        //
        // It probably means that this structure just isn't the right
        // one.
        //
        // The ugliness is at least contained, though.
        event.event_metadata(EventMetadata { occurred_at:
                                                 Some(std::time::SystemTime::now().into()),
                                             ..EVENT_CORE.get::<EventCore>().to_event_metadata() });

        e.send(event.to_bytes());
    }
}

/// A lightweight handle for the event stream. All events get to the
/// event stream through this.
struct EventStream(UnboundedSender<Vec<u8>>);

impl EventStream {
    /// Queues an event to be sent out.
    fn send(&self, event: Vec<u8>) {
        trace!("About to queue an event: {:?}", event);
        if let Err(e) = self.0.unbounded_send(event) {
            error!("Failed to queue event: {:?}", e);
        }
    }
}

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

/// How long should we for the event thread to start up before
/// abandoning it and shutting down?
#[derive(Clone, Debug)]
struct EventThreadStartupWait {
    secs: u64,
}

impl Default for EventThreadStartupWait {
    fn default() -> Self { Self { secs: 5 } }
}

impl FromStr for EventThreadStartupWait {
    type Err = ParseIntError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { Ok(Self { secs: s.parse()? }) }
}

impl EnvConfig for EventThreadStartupWait {
    const ENVVAR: &'static str = "HAB_EVENT_THREAD_STARTUP_WAIT_SEC";
}

impl Into<Duration> for EventThreadStartupWait {
    fn into(self) -> Duration { Duration::from_secs(self.secs) }
}
<commit_msg>Generate a unique NATS client id for event msgs<commit_after>//! Main interface for a stream of events the Supervisor can send out
//! in the course of its operations.
//!
//! Currently, the Supervisor is able to send events to a [NATS
//! Streaming][1] server. The `init_stream` function must be called
//! before sending events to initialize the publishing thread in the
//! background. Thereafter, you can pass "event" structs to the
//! `event` function, which will publish the event to the stream.
//!
//! All events are published under the "habitat" subject.
//!
//! [1]:https://github.com/nats-io/nats-streaming-server

mod error;
// ratsio_stream is the default, but setting it as a default in Cargo.toml
// makes it trickier to use nitox instead.
#[cfg(feature = "nitox_stream")]
#[path = "event/nitox.rs"]
mod stream_impl;
#[cfg(any(feature = "ratsio_stream", not(feature = "nitox_stream")))]
#[path = "event/ratsio.rs"]
mod stream_impl;
mod types;

pub(crate) use self::types::ServiceMetadata;
use self::types::{EventMessage,
                  EventMetadata,
                  HealthCheckEvent,
                  ServiceStartedEvent,
                  ServiceStoppedEvent};
use crate::manager::{service::{HealthCheckResult,
                               Service},
                     sys::Sys};
use clap::ArgMatches;
pub use error::{Error,
                Result};
use futures::sync::mpsc::UnboundedSender;
use habitat_common::types::{AutomateAuthToken,
                            EventStreamMetadata};
use habitat_core::env::Config as EnvConfig;
use state::Container;
use std::{net::SocketAddr,
          num::ParseIntError,
          str::FromStr,
          sync::Once,
          time::Duration};

static INIT: Once = Once::new();
lazy_static! {
    // TODO (CM): When const fn support lands in stable, we can ditch
    // this lazy_static call.

    /// Reference to the event stream.
    static ref EVENT_STREAM: Container = Container::new();
    /// Core information that is shared between all events.
    static ref EVENT_CORE: Container = Container::new();
}

/// Starts a new thread for sending events to a NATS Streaming
/// server. Stashes the handle to the stream, as well as the core
/// event information that will be a part of all events, in a global
/// static reference for access later.
pub fn init_stream(config: EventStreamConfig, event_core: EventCore) -> Result<()> {
    // call_once can't return a Result (or anything), so we'll fake it
    // by hanging onto any error we might receive.
    let mut return_value: Result<()> = Ok(());

    INIT.call_once(|| {
            let conn_info = EventConnectionInfo::new(config.token, config.url,
                                                     event_core.supervisor_id.clone());
            match stream_impl::init_stream(conn_info) {
                Ok(event_stream) => {
                    EVENT_STREAM.set(event_stream);
                    EVENT_CORE.set(event_core);
                }
                Err(e) => return_value = Err(e),
            }
        });

    return_value
}

/// Captures all event stream-related configuration options that would
/// be passed in by a user
#[derive(Clone, Debug)]
pub struct EventStreamConfig {
    environment: String,
    application: String,
    site:        Option<String>,
    meta:        EventStreamMetadata,
    token:       AutomateAuthToken,
    url:         String,
}

impl<'a> From<&'a ArgMatches<'a>> for EventStreamConfig {
    fn from(m: &ArgMatches) -> Self {
        EventStreamConfig { environment: m.value_of("EVENT_STREAM_ENVIRONMENT")
                                          .map(str::to_string)
                                          .expect("Required option for EventStream feature"),
                            application: m.value_of("EVENT_STREAM_APPLICATION")
                                          .map(str::to_string)
                                          .expect("Required option for EventStream feature"),
                            site:        m.value_of("EVENT_STREAM_SITE").map(str::to_string),
                            meta:        EventStreamMetadata::from(m),
                            token:       AutomateAuthToken::from(m),
                            url:         m.value_of("EVENT_STREAM_URL")
                                          .map(str::to_string)
                                          .expect("Required option for EventStream feature"), }
    }
}

/// All the information needed to establish a connection to a NATS
/// Streaming server.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
    pub auth_token:  AutomateAuthToken,
}

impl EventConnectionInfo {
    pub fn new(auth_token: AutomateAuthToken, cluster_uri: String, supervisor_id: String) -> Self {
        EventConnectionInfo { name: format!("hab_client_{}", supervisor_id),
                              verbose: true,
                              cluster_uri,
                              cluster_id: "event-service".to_string(),
                              auth_token }
    }
}

/// A collection of data that will be present in all events. Rather
/// than baking this into the structure of each event, we represent it
/// once and merge the information into the final rendered form of the
/// event.
///
/// This prevents us from having to thread information throughout the
/// system, just to get it to the places where the events are
/// generated (e.g., not all code has direct access to the
/// Supervisor's ID).
#[derive(Clone, Debug)]
pub struct EventCore {
    /// The unique identifier of the Supervisor sending the event.
    supervisor_id: String,
    ip_address: SocketAddr,
    fqdn: String,
    application: String,
    environment: String,
    site: Option<String>,
    meta: EventStreamMetadata,
}

impl EventCore {
    pub fn new(config: &EventStreamConfig, sys: &Sys, fqdn: String) -> Self {
        EventCore { supervisor_id: sys.member_id.clone(),
                    ip_address: sys.gossip_listen(),
                    fqdn,
                    environment: config.environment.clone(),
                    application: config.application.clone(),
                    site: config.site.clone(),
                    meta: config.meta.clone() }
    }
}

/// Send an event for the start of a Service.
pub fn service_started(service: &Service) {
    if stream_initialized() {
        publish(ServiceStartedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

/// Send an event for the stop of a Service.
pub fn service_stopped(service: &Service) {
    if stream_initialized() {
        publish(ServiceStoppedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

// Takes metadata directly, rather than a `&Service` like other event
// functions, because of how the asynchronous health checking
// currently works. Revisit when async/await + Pin is all stabilized.
/// `execution` will be `Some` if the service had a hook to run, and
/// records how long it took that hook to execute completely.
pub fn health_check(metadata: ServiceMetadata,
                    check_result: HealthCheckResult,
                    execution: Option<Duration>) {
    if stream_initialized() {
        let check_result: types::HealthCheckResult = check_result.into();
        publish(HealthCheckEvent { service_metadata: Some(metadata),
                                   event_metadata:   None,
                                   result:           i32::from(check_result),
                                   execution:        execution.map(Duration::into), });
    }
}

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

/// Internal helper function to know whether or not to go to the trouble of
/// creating event structures. If the event stream hasn't been
/// initialized, then we shouldn't need to do anything.
fn stream_initialized() -> bool { EVENT_STREAM.try_get::<EventStream>().is_some() }

/// Publish an event. This is the main interface that client code will
/// use.
///
/// If `init_stream` has not been called already, this function will
/// be a no-op.
fn publish(mut event: impl EventMessage) {
    if let Some(e) = EVENT_STREAM.try_get::<EventStream>() {
        // TODO (CM): Yeah... this is looking pretty gross. The
        // intention is to be able to timestamp the events right as
        // they go out.
        //
        // We *could* set the time when we convert the EventCore to a
        // EventMetadata struct, but that seems odd.
        //
        // It probably means that this structure just isn't the right
        // one.
        //
        // The ugliness is at least contained, though.
        event.event_metadata(EventMetadata { occurred_at:
                                                 Some(std::time::SystemTime::now().into()),
                                             ..EVENT_CORE.get::<EventCore>().to_event_metadata() });

        e.send(event.to_bytes());
    }
}

/// A lightweight handle for the event stream. All events get to the
/// event stream through this.
struct EventStream(UnboundedSender<Vec<u8>>);

impl EventStream {
    /// Queues an event to be sent out.
    fn send(&self, event: Vec<u8>) {
        trace!("About to queue an event: {:?}", event);
        if let Err(e) = self.0.unbounded_send(event) {
            error!("Failed to queue event: {:?}", e);
        }
    }
}

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

/// How long should we for the event thread to start up before
/// abandoning it and shutting down?
#[derive(Clone, Debug)]
struct EventThreadStartupWait {
    secs: u64,
}

impl Default for EventThreadStartupWait {
    fn default() -> Self { Self { secs: 5 } }
}

impl FromStr for EventThreadStartupWait {
    type Err = ParseIntError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { Ok(Self { secs: s.parse()? }) }
}

impl EnvConfig for EventThreadStartupWait {
    const ENVVAR: &'static str = "HAB_EVENT_THREAD_STARTUP_WAIT_SEC";
}

impl Into<Duration> for EventThreadStartupWait {
    fn into(self) -> Duration { Duration::from_secs(self.secs) }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![feature(path_ext)]

extern crate tempdir;

use std::env;
use std::fs;
use std::io::prelude::*;
use std::path::Path;
use std::sync::mpsc::channel;
use std::thread;

use tempdir::TempDir;

macro_rules! t {
    ($e:expr) => (match $e { Ok(n) => n, Err(e) => panic!("error: {}", e) })
}

fn test_tempdir() {
    let path = {
        let p = t!(TempDir::new_in(&Path::new("."), "foobar"));
        let p = p.path();
        assert!(p.to_str().unwrap().contains("foobar"));
        p.to_path_buf()
    };
    assert!(!path.exists());
}

fn test_rm_tempdir() {
    let (tx, rx) = channel();
    let f = move|| -> () {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        tx.send(tmp.path().to_path_buf()).unwrap();
        panic!("panic to unwind past `tmp`");
    };
    let _ = thread::spawn(f).join();
    let path = rx.recv().unwrap();
    assert!(!path.exists());

    let tmp = t!(TempDir::new("test_rm_tempdir"));
    let path = tmp.path().to_path_buf();
    let f = move|| -> () {
        let _tmp = tmp;
        panic!("panic to unwind past `tmp`");
    };
    let _ = thread::spawn(f).join();
    assert!(!path.exists());

    let path;
    {
        let f = move || {
            t!(TempDir::new("test_rm_tempdir"))
        };
        // FIXME(#16640) `: TempDir` annotation shouldn't be necessary
        let tmp: TempDir = thread::scoped(f).join();
        path = tmp.path().to_path_buf();
        assert!(path.exists());
    }
    assert!(!path.exists());

    let path;
    {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        path = tmp.into_path();
    }
    assert!(path.exists());
    t!(fs::remove_dir_all(&path));
    assert!(!path.exists());
}

fn test_rm_tempdir_close() {
    let (tx, rx) = channel();
    let f = move|| -> () {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        tx.send(tmp.path().to_path_buf()).unwrap();
        t!(tmp.close());
        panic!("panic when unwinding past `tmp`");
    };
    let _ = thread::spawn(f).join();
    let path = rx.recv().unwrap();
    assert!(!path.exists());

    let tmp = t!(TempDir::new("test_rm_tempdir"));
    let path = tmp.path().to_path_buf();
    let f = move|| -> () {
        let tmp = tmp;
        t!(tmp.close());
        panic!("panic when unwinding past `tmp`");
    };
    let _ = thread::spawn(f).join();
    assert!(!path.exists());

    let path;
    {
        let f = move || {
            t!(TempDir::new("test_rm_tempdir"))
        };
        // FIXME(#16640) `: TempDir` annotation shouldn't be necessary
        let tmp: TempDir = thread::scoped(f).join();
        path = tmp.path().to_path_buf();
        assert!(path.exists());
        t!(tmp.close());
    }
    assert!(!path.exists());

    let path;
    {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        path = tmp.into_path();
    }
    assert!(path.exists());
    t!(fs::remove_dir_all(&path));
    assert!(!path.exists());
}

// Ideally these would be in std::os but then core would need
// to depend on std
fn recursive_mkdir_rel() {
    let path = Path::new("frob");
    let cwd = env::current_dir().unwrap();
    println!("recursive_mkdir_rel: Making: {} in cwd {} [{}]", path.display(),
           cwd.display(), path.exists());
    t!(fs::create_dir(&path));
    assert!(path.is_dir());
    t!(fs::create_dir_all(&path));
    assert!(path.is_dir());
}

fn recursive_mkdir_dot() {
    let dot = Path::new(".");
    t!(fs::create_dir_all(&dot));
    let dotdot = Path::new("..");
    t!(fs::create_dir_all(&dotdot));
}

fn recursive_mkdir_rel_2() {
    let path = Path::new("./frob/baz");
    let cwd = env::current_dir().unwrap();
    println!("recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", path.display(),
             cwd.display(), path.exists());
    t!(fs::create_dir_all(&path));
    assert!(path.is_dir());
    assert!(path.parent().unwrap().is_dir());
    let path2 = Path::new("quux/blat");
    println!("recursive_mkdir_rel_2: Making: {} in cwd {}", path2.display(),
             cwd.display());
    t!(fs::create_dir("quux"));
    t!(fs::create_dir_all(&path2));
    assert!(path2.is_dir());
    assert!(path2.parent().unwrap().is_dir());
}

// Ideally this would be in core, but needs TempFile
pub fn test_remove_dir_all_ok() {
    let tmpdir = t!(TempDir::new("test"));
    let tmpdir = tmpdir.path();
    let root = tmpdir.join("foo");

    println!("making {}", root.display());
    t!(fs::create_dir(&root));
    t!(fs::create_dir(&root.join("foo")));
    t!(fs::create_dir(&root.join("foo").join("bar")));
    t!(fs::create_dir(&root.join("foo").join("bar").join("blat")));
    t!(fs::remove_dir_all(&root));
    assert!(!root.exists());
    assert!(!root.join("bar").exists());
    assert!(!root.join("bar").join("blat").exists());
}

pub fn dont_double_panic() {
    let r: Result<(), _> = thread::spawn(move|| {
        let tmpdir = TempDir::new("test").unwrap();
        // Remove the temporary directory so that TempDir sees
        // an error on drop
        t!(fs::remove_dir(tmpdir.path()));
        // Panic. If TempDir panics *again* due to the rmdir
        // error then the process will abort.
        panic!();
    }).join();
    assert!(r.is_err());
}

fn in_tmpdir<F>(f: F) where F: FnOnce() {
    let tmpdir = t!(TempDir::new("test"));
    assert!(env::set_current_dir(tmpdir.path()).is_ok());

    f();
}

#[test]
fn main() {
    in_tmpdir(test_tempdir);
    in_tmpdir(test_rm_tempdir);
    in_tmpdir(test_rm_tempdir_close);
    in_tmpdir(recursive_mkdir_rel);
    in_tmpdir(recursive_mkdir_dot);
    in_tmpdir(recursive_mkdir_rel_2);
    in_tmpdir(test_remove_dir_all_ok);
    in_tmpdir(dont_double_panic);
}
<commit_msg>Update to rust master<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![feature(path_ext)]

extern crate tempdir;

use std::env;
use std::fs;
use std::io::prelude::*;
use std::path::Path;
use std::sync::mpsc::channel;
use std::thread;

use tempdir::TempDir;

macro_rules! t {
    ($e:expr) => (match $e { Ok(n) => n, Err(e) => panic!("error: {}", e) })
}

fn test_tempdir() {
    let path = {
        let p = t!(TempDir::new_in(&Path::new("."), "foobar"));
        let p = p.path();
        assert!(p.to_str().unwrap().contains("foobar"));
        p.to_path_buf()
    };
    assert!(!path.exists());
}

fn test_rm_tempdir() {
    let (tx, rx) = channel();
    let f = move|| -> () {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        tx.send(tmp.path().to_path_buf()).unwrap();
        panic!("panic to unwind past `tmp`");
    };
    let _ = thread::spawn(f).join();
    let path = rx.recv().unwrap();
    assert!(!path.exists());

    let tmp = t!(TempDir::new("test_rm_tempdir"));
    let path = tmp.path().to_path_buf();
    let f = move|| -> () {
        let _tmp = tmp;
        panic!("panic to unwind past `tmp`");
    };
    let _ = thread::spawn(f).join();
    assert!(!path.exists());

    let path;
    {
        let f = move || {
            t!(TempDir::new("test_rm_tempdir"))
        };
        // FIXME(#16640) `: TempDir` annotation shouldn't be necessary
        let tmp: TempDir = thread::spawn(f).join().unwrap();
        path = tmp.path().to_path_buf();
        assert!(path.exists());
    }
    assert!(!path.exists());

    let path;
    {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        path = tmp.into_path();
    }
    assert!(path.exists());
    t!(fs::remove_dir_all(&path));
    assert!(!path.exists());
}

fn test_rm_tempdir_close() {
    let (tx, rx) = channel();
    let f = move|| -> () {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        tx.send(tmp.path().to_path_buf()).unwrap();
        t!(tmp.close());
        panic!("panic when unwinding past `tmp`");
    };
    let _ = thread::spawn(f).join();
    let path = rx.recv().unwrap();
    assert!(!path.exists());

    let tmp = t!(TempDir::new("test_rm_tempdir"));
    let path = tmp.path().to_path_buf();
    let f = move|| -> () {
        let tmp = tmp;
        t!(tmp.close());
        panic!("panic when unwinding past `tmp`");
    };
    let _ = thread::spawn(f).join();
    assert!(!path.exists());

    let path;
    {
        let f = move || {
            t!(TempDir::new("test_rm_tempdir"))
        };
        // FIXME(#16640) `: TempDir` annotation shouldn't be necessary
        let tmp: TempDir = thread::spawn(f).join().unwrap();
        path = tmp.path().to_path_buf();
        assert!(path.exists());
        t!(tmp.close());
    }
    assert!(!path.exists());

    let path;
    {
        let tmp = t!(TempDir::new("test_rm_tempdir"));
        path = tmp.into_path();
    }
    assert!(path.exists());
    t!(fs::remove_dir_all(&path));
    assert!(!path.exists());
}

// Ideally these would be in std::os but then core would need
// to depend on std
fn recursive_mkdir_rel() {
    let path = Path::new("frob");
    let cwd = env::current_dir().unwrap();
    println!("recursive_mkdir_rel: Making: {} in cwd {} [{}]", path.display(),
           cwd.display(), path.exists());
    t!(fs::create_dir(&path));
    assert!(path.is_dir());
    t!(fs::create_dir_all(&path));
    assert!(path.is_dir());
}

fn recursive_mkdir_dot() {
    let dot = Path::new(".");
    t!(fs::create_dir_all(&dot));
    let dotdot = Path::new("..");
    t!(fs::create_dir_all(&dotdot));
}

fn recursive_mkdir_rel_2() {
    let path = Path::new("./frob/baz");
    let cwd = env::current_dir().unwrap();
    println!("recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", path.display(),
             cwd.display(), path.exists());
    t!(fs::create_dir_all(&path));
    assert!(path.is_dir());
    assert!(path.parent().unwrap().is_dir());
    let path2 = Path::new("quux/blat");
    println!("recursive_mkdir_rel_2: Making: {} in cwd {}", path2.display(),
             cwd.display());
    t!(fs::create_dir("quux"));
    t!(fs::create_dir_all(&path2));
    assert!(path2.is_dir());
    assert!(path2.parent().unwrap().is_dir());
}

// Ideally this would be in core, but needs TempFile
pub fn test_remove_dir_all_ok() {
    let tmpdir = t!(TempDir::new("test"));
    let tmpdir = tmpdir.path();
    let root = tmpdir.join("foo");

    println!("making {}", root.display());
    t!(fs::create_dir(&root));
    t!(fs::create_dir(&root.join("foo")));
    t!(fs::create_dir(&root.join("foo").join("bar")));
    t!(fs::create_dir(&root.join("foo").join("bar").join("blat")));
    t!(fs::remove_dir_all(&root));
    assert!(!root.exists());
    assert!(!root.join("bar").exists());
    assert!(!root.join("bar").join("blat").exists());
}

pub fn dont_double_panic() {
    let r: Result<(), _> = thread::spawn(move|| {
        let tmpdir = TempDir::new("test").unwrap();
        // Remove the temporary directory so that TempDir sees
        // an error on drop
        t!(fs::remove_dir(tmpdir.path()));
        // Panic. If TempDir panics *again* due to the rmdir
        // error then the process will abort.
        panic!();
    }).join();
    assert!(r.is_err());
}

fn in_tmpdir<F>(f: F) where F: FnOnce() {
    let tmpdir = t!(TempDir::new("test"));
    assert!(env::set_current_dir(tmpdir.path()).is_ok());

    f();
}

#[test]
fn main() {
    in_tmpdir(test_tempdir);
    in_tmpdir(test_rm_tempdir);
    in_tmpdir(test_rm_tempdir_close);
    in_tmpdir(recursive_mkdir_rel);
    in_tmpdir(recursive_mkdir_dot);
    in_tmpdir(recursive_mkdir_rel_2);
    in_tmpdir(test_remove_dir_all_ok);
    in_tmpdir(dont_double_panic);
}
<|endoftext|>


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

pub fn brackets_are_balanced(string: &str) -> bool {
    Brackets::from(string).are_balanced()
}

struct Brackets {
    raw_brackets: Vec<char>,
    pairs: MatchingBrackets,
}

impl<'a> From<&'a str> for Brackets {
    fn from(i: &str) -> Self {
        Brackets::new(i, None)
    }
}

impl Brackets {
    fn new(s: &str, pairs: Option<Vec<(char, char)>>) -> Self {
        let p = match pairs {
            Some(x) => MatchingBrackets::from(x),
            None => MatchingBrackets::from(vec![('[', ']'), ('{', '}'), ('(', ')')]),
        };

        Brackets {
            raw_brackets: s.chars().filter(|c| p.contains(&c)).collect::<Vec<char>>(),
            pairs: p,
        }
    }

    fn are_balanced(&self) -> bool {
        let mut unclosed: Vec<char> = Vec::new();

        for &bracket in self.raw_brackets.iter() {
            if let Some(last_unclosed) = unclosed.pop() {
                unclosed.extend(self.pairs.unmatched(last_unclosed, bracket));
            } else {
                unclosed.push(bracket);
            }
        }

        unclosed.is_empty()
    }
}

struct MatchingBrackets {
    collection: HashMap<char, char>,
}

impl From<Vec<(char, char)>> for MatchingBrackets {
    fn from(v: Vec<(char, char)>) -> Self {
        MatchingBrackets {
            collection: v.into_iter().collect::<HashMap<char, char>>(),
        }
    }
}

impl MatchingBrackets {
    fn contains(&self, other: &char) -> bool {
        let known = self
            .collection
            .keys()
            .chain(self.collection.values())
            .collect::<Vec<_>>();
        known.contains(&other)
    }

    fn closer_for(&self, k: &char) -> Option<&char> {
        self.collection.get(k)
    }

    fn closed_by(&self, l: char, r: char) -> bool {
        match self.closer_for(&l) {
            Some(&x) => r == x,
            None => false,
        }
    }

    fn unmatched(&self, open: char, potential_close: char) -> Vec<char> {
        let mut ret: Vec<char> = Vec::new();

        if !self.closed_by(open, potential_close) {
            ret.push(open);
            ret.push(potential_close);
        }

        ret
    }
}
<commit_msg>matching-brackets: rm needless collect (#1023)<commit_after>use std::collections::HashMap;

pub fn brackets_are_balanced(string: &str) -> bool {
    Brackets::from(string).are_balanced()
}

struct Brackets {
    raw_brackets: Vec<char>,
    pairs: MatchingBrackets,
}

impl<'a> From<&'a str> for Brackets {
    fn from(i: &str) -> Self {
        Brackets::new(i, None)
    }
}

impl Brackets {
    fn new(s: &str, pairs: Option<Vec<(char, char)>>) -> Self {
        let p = match pairs {
            Some(x) => MatchingBrackets::from(x),
            None => MatchingBrackets::from(vec![('[', ']'), ('{', '}'), ('(', ')')]),
        };

        Brackets {
            raw_brackets: s.chars().filter(|c| p.contains(&c)).collect::<Vec<char>>(),
            pairs: p,
        }
    }

    fn are_balanced(&self) -> bool {
        let mut unclosed: Vec<char> = Vec::new();

        for &bracket in self.raw_brackets.iter() {
            if let Some(last_unclosed) = unclosed.pop() {
                unclosed.extend(self.pairs.unmatched(last_unclosed, bracket));
            } else {
                unclosed.push(bracket);
            }
        }

        unclosed.is_empty()
    }
}

struct MatchingBrackets {
    collection: HashMap<char, char>,
}

impl From<Vec<(char, char)>> for MatchingBrackets {
    fn from(v: Vec<(char, char)>) -> Self {
        MatchingBrackets {
            collection: v.into_iter().collect::<HashMap<char, char>>(),
        }
    }
}

impl MatchingBrackets {
    fn contains(&self, other: &char) -> bool {
        self.collection
            .iter()
            .any(|(k, v)| k == other || v == other)
    }

    fn closer_for(&self, k: &char) -> Option<&char> {
        self.collection.get(k)
    }

    fn closed_by(&self, l: char, r: char) -> bool {
        match self.closer_for(&l) {
            Some(&x) => r == x,
            None => false,
        }
    }

    fn unmatched(&self, open: char, potential_close: char) -> Vec<char> {
        let mut ret: Vec<char> = Vec::new();

        if !self.closed_by(open, potential_close) {
            ret.push(open);
            ret.push(potential_close);
        }

        ret
    }
}
<|endoftext|>


<commit_before>pub fn rotate(input: &str, key: u8) -> String {
    unimplemented!(
        "How would input text '{}' transform when every letter is shifted using key '{}'?",
        input,
        key
    );
}
<commit_msg>rotational-cipher: Changed key type from u8 to i8 in the rotate function template<commit_after>pub fn rotate(input: &str, key: i8) -> String {
    unimplemented!(
        "How would input text '{}' transform when every letter is shifted using key '{}'?",
        input,
        key
    );
}
<|endoftext|>


<commit_before>extern crate space_age;

use space_age::*;

fn assert_in_delta(expected: f64, actual: f64) {
    let diff: f64 = expected - actual.abs();
    let delta: f64 = 0.01;
    if diff > delta {
        panic!("Your result of {} should be within {} of the expected result {}",
               actual,
               delta,
               expected)
    }
}

#[test]
fn earth_age() {
    let duration = Duration::from(1_000_000_000);
    assert_in_delta(31.69, Earth::years_during(&duration));
}

#[test]
#[ignore]
fn mercury_age() {
    let duration = Duration::from(2_134_835_688);
    assert_in_delta(280.88, Mercury::years_during(&duration));
}

#[test]
#[ignore]
fn venus_age() {
    let duration = Duration::from(189_839_836);
    assert_in_delta(9.78, Venus::years_during(&duration));
}

#[test]
#[ignore]
fn mars_age() {
    let duration = Duration::from(2_329_871_239);
    assert_in_delta(39.25, Mars::years_during(&duration));
}

#[test]
#[ignore]
fn jupiter_age() {
    let duration = Duration::from(901_876_382);
    assert_in_delta(2.41, Jupiter::years_during(&duration));
}

#[test]
#[ignore]
fn saturn_age() {
    let duration = Duration::from(3_000_000_000);
    assert_in_delta(3.23, Saturn::years_during(&duration));
}

#[test]
#[ignore]
fn uranus_age() {
    let duration = Duration::from(3_210_123_456);
    assert_in_delta(1.21, Uranus::years_during(&duration));
}

#[test]
#[ignore]
fn neptune_age() {
    let duration = Duration::from(8_210_123_456);
    assert_in_delta(1.58, Neptune::years_during(&duration));
}
<commit_msg>space_age: properly check float delta<commit_after>extern crate space_age;

use space_age::*;

fn assert_in_delta(expected: f64, actual: f64) {
    let diff: f64 = (expected - actual).abs();
    let delta: f64 = 0.01;
    if diff > delta {
        panic!("Your result of {} should be within {} of the expected result {}",
               actual,
               delta,
               expected)
    }
}

#[test]
fn earth_age() {
    let duration = Duration::from(1_000_000_000);
    assert_in_delta(31.69, Earth::years_during(&duration));
}

#[test]
#[ignore]
fn mercury_age() {
    let duration = Duration::from(2_134_835_688);
    assert_in_delta(280.88, Mercury::years_during(&duration));
}

#[test]
#[ignore]
fn venus_age() {
    let duration = Duration::from(189_839_836);
    assert_in_delta(9.78, Venus::years_during(&duration));
}

#[test]
#[ignore]
fn mars_age() {
    let duration = Duration::from(2_329_871_239);
    assert_in_delta(39.25, Mars::years_during(&duration));
}

#[test]
#[ignore]
fn jupiter_age() {
    let duration = Duration::from(901_876_382);
    assert_in_delta(2.41, Jupiter::years_during(&duration));
}

#[test]
#[ignore]
fn saturn_age() {
    let duration = Duration::from(3_000_000_000);
    assert_in_delta(3.23, Saturn::years_during(&duration));
}

#[test]
#[ignore]
fn uranus_age() {
    let duration = Duration::from(3_210_123_456);
    assert_in_delta(1.21, Uranus::years_during(&duration));
}

#[test]
#[ignore]
fn neptune_age() {
    let duration = Duration::from(8_210_123_456);
    assert_in_delta(1.58, Neptune::years_during(&duration));
}
<|endoftext|>


<commit_before>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// 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.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

use clap::Clap;

use std::ffi::{CString, OsStr};
use std::num::ParseIntError;
use std::path::PathBuf;

#[derive(Clap, PartialEq, Debug)]
struct PathOpt {
    #[clap(short, long, parse(from_os_str))]
    path: PathBuf,

    #[clap(short, default_value = "../", parse(from_os_str))]
    default_path: PathBuf,

    #[clap(short, parse(from_os_str))]
    vector_path: Vec<PathBuf>,

    #[clap(short, parse(from_os_str))]
    option_path_1: Option<PathBuf>,

    #[clap(short = 'q', parse(from_os_str))]
    option_path_2: Option<PathBuf>,
}

#[test]
fn test_path_opt_simple() {
    assert_eq!(
        PathOpt {
            path: PathBuf::from("/usr/bin"),
            default_path: PathBuf::from("../"),
            vector_path: vec![
                PathBuf::from("/a/b/c"),
                PathBuf::from("/d/e/f"),
                PathBuf::from("/g/h/i"),
            ],
            option_path_1: None,
            option_path_2: Some(PathBuf::from("j.zip")),
        },
        PathOpt::parse_from(&[
            "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q",
            "j.zip",
        ])
    );
}

fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
    u64::from_str_radix(input, 16)
}

#[derive(Clap, PartialEq, Debug)]
struct HexOpt {
    #[clap(short, parse(try_from_str = parse_hex))]
    number: u64,
}

#[test]
fn test_parse_hex() {
    assert_eq!(
        HexOpt { number: 5 },
        HexOpt::parse_from(&["test", "-n", "5"])
    );
    assert_eq!(
        HexOpt {
            number: 0x00ab_cdef
        },
        HexOpt::parse_from(&["test", "-n", "abcdef"])
    );

    let err = HexOpt::try_parse_from(&["test", "-n", "gg"]).unwrap_err();
    assert!(
        err.to_string().contains("invalid digit found in string"),
        err
    );
}

fn custom_parser_1(_: &str) -> &'static str {
    "A"
}
#[derive(Debug)]
struct ErrCode(u32);
impl std::error::Error for ErrCode {}
impl std::fmt::Display for ErrCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&self.0, f)
    }
}
fn custom_parser_2(_: &str) -> Result<&'static str, ErrCode> {
    Ok("B")
}
fn custom_parser_3(_: &OsStr) -> &'static str {
    "C"
}
fn custom_parser_4(_: &OsStr) -> Result<&'static str, String> {
    Ok("D")
}

#[derive(Clap, PartialEq, Debug)]
struct NoOpOpt {
    #[clap(short, parse(from_str = custom_parser_1))]
    a: &'static str,
    #[clap(short, parse(try_from_str = custom_parser_2))]
    b: &'static str,
    #[clap(short, parse(from_os_str = custom_parser_3))]
    c: &'static str,
    #[clap(short, parse(try_from_os_str = custom_parser_4))]
    d: &'static str,
}

#[test]
fn test_every_custom_parser() {
    assert_eq!(
        NoOpOpt {
            a: "A",
            b: "B",
            c: "C",
            d: "D"
        },
        NoOpOpt::parse_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"])
    );
}

#[test]
fn update_every_custom_parser() {
    let mut opt = NoOpOpt {
        a: "0",
        b: "0",
        c: "0",
        d: "D",
    };

    opt.update_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"]);

    assert_eq!(
        NoOpOpt {
            a: "A",
            b: "B",
            c: "C",
            d: "D"
        },
        opt
    );
}

// Note: can't use `Vec<u8>` directly, as clap would instead look for
// conversion function from `&str` to `u8`.
type Bytes = Vec<u8>;

#[derive(Clap, PartialEq, Debug)]
struct DefaultedOpt {
    #[clap(short, parse(from_str))]
    bytes: Bytes,

    #[clap(short, parse(try_from_str))]
    integer: u64,

    #[clap(short, parse(from_os_str))]
    path: PathBuf,
}

#[test]
fn test_parser_with_default_value() {
    assert_eq!(
        DefaultedOpt {
            bytes: b"E\xc2\xb2=p\xc2\xb2c\xc2\xb2+m\xc2\xb2c\xe2\x81\xb4".to_vec(),
            integer: 9000,
            path: PathBuf::from("src/lib.rs"),
        },
        DefaultedOpt::parse_from(&[
            "test",
            "-b",
            "E²=p²c²+m²c⁴",
            "-i",
            "9000",
            "-p",
            "src/lib.rs",
        ])
    );
}

#[derive(PartialEq, Debug)]
struct Foo(u8);

fn foo(value: u64) -> Foo {
    Foo(value as u8)
}

#[derive(Clap, PartialEq, Debug)]
struct Occurrences {
    #[clap(short, long, parse(from_occurrences))]
    signed: i32,

    #[clap(short, parse(from_occurrences))]
    little_signed: i8,

    #[clap(short, parse(from_occurrences))]
    unsigned: usize,

    #[clap(short = 'r', parse(from_occurrences))]
    little_unsigned: u8,

    #[clap(short, long, parse(from_occurrences = foo))]
    custom: Foo,
}

#[test]
fn test_parser_occurrences() {
    assert_eq!(
        Occurrences {
            signed: 3,
            little_signed: 1,
            unsigned: 0,
            little_unsigned: 4,
            custom: Foo(5),
        },
        Occurrences::parse_from(&[
            "test", "-s", "--signed", "--signed", "-l", "-rrrr", "-cccc", "--custom",
        ])
    );
}

#[test]
fn test_custom_bool() {
    fn parse_bool(s: &str) -> Result<bool, String> {
        match s {
            "true" => Ok(true),
            "false" => Ok(false),
            _ => Err(format!("invalid bool {}", s)),
        }
    }
    #[derive(Clap, PartialEq, Debug)]
    struct Opt {
        #[clap(short, parse(try_from_str = parse_bool))]
        debug: bool,
        #[clap(
            short,
            default_value = "false",
            parse(try_from_str = parse_bool)
        )]
        verbose: bool,
        #[clap(short, parse(try_from_str = parse_bool))]
        tribool: Option<bool>,
        #[clap(short, parse(try_from_str = parse_bool))]
        bitset: Vec<bool>,
    }

    assert!(Opt::try_parse_from(&["test"]).is_err());
    assert!(Opt::try_parse_from(&["test", "-d"]).is_err());
    assert!(Opt::try_parse_from(&["test", "-dfoo"]).is_err());
    assert_eq!(
        Opt {
            debug: false,
            verbose: false,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dfalse"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-vfalse"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: true,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-vtrue"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: Some(false),
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-tfalse"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: Some(true),
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-ttrue"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: None,
            bitset: vec![false, true, false, false],
        },
        Opt::parse_from(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"])
    );
}

#[test]
fn test_cstring() {
    #[derive(Clap)]
    struct Opt {
        #[clap(parse(try_from_str = CString::new))]
        c_string: CString,
    }

    assert!(Opt::try_parse_from(&["test"]).is_err());
    assert_eq!(
        Opt::parse_from(&["test", "bla"]).c_string.to_bytes(),
        b"bla"
    );
    assert!(Opt::try_parse_from(&["test", "bla\0bla"]).is_err());
}
<commit_msg>Test for partial updates<commit_after>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// 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.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

use clap::Clap;

use std::ffi::{CString, OsStr};
use std::num::ParseIntError;
use std::path::PathBuf;

#[derive(Clap, PartialEq, Debug)]
struct PathOpt {
    #[clap(short, long, parse(from_os_str))]
    path: PathBuf,

    #[clap(short, default_value = "../", parse(from_os_str))]
    default_path: PathBuf,

    #[clap(short, parse(from_os_str))]
    vector_path: Vec<PathBuf>,

    #[clap(short, parse(from_os_str))]
    option_path_1: Option<PathBuf>,

    #[clap(short = 'q', parse(from_os_str))]
    option_path_2: Option<PathBuf>,
}

#[test]
fn test_path_opt_simple() {
    assert_eq!(
        PathOpt {
            path: PathBuf::from("/usr/bin"),
            default_path: PathBuf::from("../"),
            vector_path: vec![
                PathBuf::from("/a/b/c"),
                PathBuf::from("/d/e/f"),
                PathBuf::from("/g/h/i"),
            ],
            option_path_1: None,
            option_path_2: Some(PathBuf::from("j.zip")),
        },
        PathOpt::parse_from(&[
            "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q",
            "j.zip",
        ])
    );
}

fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
    u64::from_str_radix(input, 16)
}

#[derive(Clap, PartialEq, Debug)]
struct HexOpt {
    #[clap(short, parse(try_from_str = parse_hex))]
    number: u64,
}

#[test]
fn test_parse_hex() {
    assert_eq!(
        HexOpt { number: 5 },
        HexOpt::parse_from(&["test", "-n", "5"])
    );
    assert_eq!(
        HexOpt {
            number: 0x00ab_cdef
        },
        HexOpt::parse_from(&["test", "-n", "abcdef"])
    );

    let err = HexOpt::try_parse_from(&["test", "-n", "gg"]).unwrap_err();
    assert!(
        err.to_string().contains("invalid digit found in string"),
        err
    );
}

fn custom_parser_1(_: &str) -> &'static str {
    "A"
}
#[derive(Debug)]
struct ErrCode(u32);
impl std::error::Error for ErrCode {}
impl std::fmt::Display for ErrCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Display::fmt(&self.0, f)
    }
}
fn custom_parser_2(_: &str) -> Result<&'static str, ErrCode> {
    Ok("B")
}
fn custom_parser_3(_: &OsStr) -> &'static str {
    "C"
}
fn custom_parser_4(_: &OsStr) -> Result<&'static str, String> {
    Ok("D")
}

#[derive(Clap, PartialEq, Debug)]
struct NoOpOpt {
    #[clap(short, parse(from_str = custom_parser_1))]
    a: &'static str,
    #[clap(short, parse(try_from_str = custom_parser_2))]
    b: &'static str,
    #[clap(short, parse(from_os_str = custom_parser_3))]
    c: &'static str,
    #[clap(short, parse(try_from_os_str = custom_parser_4))]
    d: &'static str,
}

#[test]
fn test_every_custom_parser() {
    assert_eq!(
        NoOpOpt {
            a: "A",
            b: "B",
            c: "C",
            d: "D"
        },
        NoOpOpt::parse_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"])
    );
}

#[test]
fn update_every_custom_parser() {
    let mut opt = NoOpOpt {
        a: "0",
        b: "0",
        c: "0",
        d: "D",
    };

    opt.update_from(&["test", "-a=?", "-b=?", "-d=?"]);

    assert_eq!(
        NoOpOpt {
            a: "A",
            b: "B",
            c: "0",
            d: "D"
        },
        opt
    );
}

// Note: can't use `Vec<u8>` directly, as clap would instead look for
// conversion function from `&str` to `u8`.
type Bytes = Vec<u8>;

#[derive(Clap, PartialEq, Debug)]
struct DefaultedOpt {
    #[clap(short, parse(from_str))]
    bytes: Bytes,

    #[clap(short, parse(try_from_str))]
    integer: u64,

    #[clap(short, parse(from_os_str))]
    path: PathBuf,
}

#[test]
fn test_parser_with_default_value() {
    assert_eq!(
        DefaultedOpt {
            bytes: b"E\xc2\xb2=p\xc2\xb2c\xc2\xb2+m\xc2\xb2c\xe2\x81\xb4".to_vec(),
            integer: 9000,
            path: PathBuf::from("src/lib.rs"),
        },
        DefaultedOpt::parse_from(&[
            "test",
            "-b",
            "E²=p²c²+m²c⁴",
            "-i",
            "9000",
            "-p",
            "src/lib.rs",
        ])
    );
}

#[derive(PartialEq, Debug)]
struct Foo(u8);

fn foo(value: u64) -> Foo {
    Foo(value as u8)
}

#[derive(Clap, PartialEq, Debug)]
struct Occurrences {
    #[clap(short, long, parse(from_occurrences))]
    signed: i32,

    #[clap(short, parse(from_occurrences))]
    little_signed: i8,

    #[clap(short, parse(from_occurrences))]
    unsigned: usize,

    #[clap(short = 'r', parse(from_occurrences))]
    little_unsigned: u8,

    #[clap(short, long, parse(from_occurrences = foo))]
    custom: Foo,
}

#[test]
fn test_parser_occurrences() {
    assert_eq!(
        Occurrences {
            signed: 3,
            little_signed: 1,
            unsigned: 0,
            little_unsigned: 4,
            custom: Foo(5),
        },
        Occurrences::parse_from(&[
            "test", "-s", "--signed", "--signed", "-l", "-rrrr", "-cccc", "--custom",
        ])
    );
}

#[test]
fn test_custom_bool() {
    fn parse_bool(s: &str) -> Result<bool, String> {
        match s {
            "true" => Ok(true),
            "false" => Ok(false),
            _ => Err(format!("invalid bool {}", s)),
        }
    }
    #[derive(Clap, PartialEq, Debug)]
    struct Opt {
        #[clap(short, parse(try_from_str = parse_bool))]
        debug: bool,
        #[clap(
            short,
            default_value = "false",
            parse(try_from_str = parse_bool)
        )]
        verbose: bool,
        #[clap(short, parse(try_from_str = parse_bool))]
        tribool: Option<bool>,
        #[clap(short, parse(try_from_str = parse_bool))]
        bitset: Vec<bool>,
    }

    assert!(Opt::try_parse_from(&["test"]).is_err());
    assert!(Opt::try_parse_from(&["test", "-d"]).is_err());
    assert!(Opt::try_parse_from(&["test", "-dfoo"]).is_err());
    assert_eq!(
        Opt {
            debug: false,
            verbose: false,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dfalse"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-vfalse"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: true,
            tribool: None,
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-vtrue"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: Some(false),
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-tfalse"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: Some(true),
            bitset: vec![],
        },
        Opt::parse_from(&["test", "-dtrue", "-ttrue"])
    );
    assert_eq!(
        Opt {
            debug: true,
            verbose: false,
            tribool: None,
            bitset: vec![false, true, false, false],
        },
        Opt::parse_from(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"])
    );
}

#[test]
fn test_cstring() {
    #[derive(Clap)]
    struct Opt {
        #[clap(parse(try_from_str = CString::new))]
        c_string: CString,
    }

    assert!(Opt::try_parse_from(&["test"]).is_err());
    assert_eq!(
        Opt::parse_from(&["test", "bla"]).c_string.to_bytes(),
        b"bla"
    );
    assert!(Opt::try_parse_from(&["test", "bla\0bla"]).is_err());
}
<|endoftext|>


<commit_before>use super::{UpdateTarget, IncompleteUpdateStatement};
use super::delete_statement::DeleteStatement;

pub fn update<T: UpdateTarget>(source: T) -> IncompleteUpdateStatement<T> {
    IncompleteUpdateStatement::new(source)
}

/// Creates a delete statement. Will delete the records in the given set.
/// Because this function has a very generic name, it is not exported by
/// default.
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate yaqb;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     use yaqb::query_builder::delete;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection).unwrap().unwrap();
/// let old_count = get_count();
/// let command = delete(users.filter(id.eq(1)));
/// connection.execute_returning_count(&command).unwrap();
/// assert_eq!(old_count - 1, get_count());
/// # }
/// ```
///
/// ### Deleting a whole table:
///
/// ```rust
/// # #[macro_use] extern crate yaqb;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     use yaqb::query_builder::delete;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection).unwrap().unwrap();
/// connection.execute_returning_count(&delete(users)).unwrap();
/// assert_eq!(0, get_count());
/// # }
/// ```
pub fn delete<T: UpdateTarget>(source: T) -> DeleteStatement<T> {
    DeleteStatement::new(source)
}
<commit_msg>Document the `update` function<commit_after>use super::{UpdateTarget, IncompleteUpdateStatement};
use super::delete_statement::DeleteStatement;

/// Creates an update statement. Helpers for updating a single row can be
/// generated by
/// [`#[changeset_for]`](https://github.com/sgrif/yaqb/tree/master/yaqb_codegen#changeset_fortable_name).
///
/// # Example
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate yaqb;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     use yaqb::query_builder::update;
/// #     let connection = establish_connection();
/// let command = update(users.filter(id.eq(1)))
///     .set(name.eq("James"));
/// let updated_row = connection.query_one(command).unwrap().unwrap();
/// // When passed to `query_one`, the update statement will gain `RETURNING *`
/// assert_eq!((1, "James".to_string()), updated_row);
/// # }
pub fn update<T: UpdateTarget>(source: T) -> IncompleteUpdateStatement<T> {
    IncompleteUpdateStatement::new(source)
}

/// Creates a delete statement. Will delete the records in the given set.
/// Because this function has a very generic name, it is not exported by
/// default.
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate yaqb;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     use yaqb::query_builder::delete;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection).unwrap().unwrap();
/// let old_count = get_count();
/// let command = delete(users.filter(id.eq(1)));
/// connection.execute_returning_count(&command).unwrap();
/// assert_eq!(old_count - 1, get_count());
/// # }
/// ```
///
/// ### Deleting a whole table:
///
/// ```rust
/// # #[macro_use] extern crate yaqb;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Serial,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     use yaqb::query_builder::delete;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection).unwrap().unwrap();
/// connection.execute_returning_count(&delete(users)).unwrap();
/// assert_eq!(0, get_count());
/// # }
/// ```
pub fn delete<T: UpdateTarget>(source: T) -> DeleteStatement<T> {
    DeleteStatement::new(source)
}
<|endoftext|>


<commit_before>use redox::*;

pub struct FileManager {
    files: Vec<String>,
    selected: isize,
}

impl FileManager {
    pub fn new() -> FileManager {
        return FileManager {
            files: Vec::new(),
            selected: -1,
        };
    }

    fn draw_content(&mut self, window: &mut Window) {
        window.set([0, 0, 0, 255]);

        let mut i = 0;
        let mut row = 0;
        for string in self.files.iter() {
            let mut col = 0;
            for c in string.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    let color;
                    if i == self.selected {
                        color = [128, 128, 128, 255];
                    } else {
                        color = [255, 255, 255, 255];
                    }

                    if col < window.width() / 8 && row < window.height() / 16 {
                        window.char(8 * col as isize, 16 * row as isize, c, color);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }
            row += 1;
            i += 1;
        }

        window.sync();
    }

    fn main(&mut self, path: String) {
        let mut width = 320;
        let mut height = 0;
        {
            let mut resource = File::open(&path);

            let mut vec: Vec<u8> = Vec::new();
            resource.read_to_end(&mut vec);

            for file in String::from_utf8(&vec).split("\n".to_string()) {
                if width < (file.len() + 1) * 8 {
                    width = (file.len() + 1) * 8;
                }
                self.files.push(file);
            }

            if height < self.files.len() * 16 {
                height = self.files.len() * 16;
            }
        }

        let mut window = Window::new((rand() % 400 + 50) as isize, (rand() % 300 + 50) as isize,
                                     width, height,
                                     &("File Manager (".to_string() + &path + ")"));

        self.draw_content(&mut window);

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            K_ESC => break,
                            K_HOME => self.selected = 0,
                            K_UP => if self.selected > 0 {
                                self.selected -= 1;
                            },
                            K_END => self.selected = self.files.len() as isize - 1,
                            K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Option::Some(file) => OpenEvent {
                                                url_string: path.clone() + file.clone(),
                                            }
                                                                      .trigger(),
                                            Option::None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file[0] == key_event.character {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }

                        self.draw_content(&mut window);
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < window.width() / 8 &&
                                   row < window.height() / 16 {
                                    if mouse_event.x >= 8 * col as isize &&
                                       mouse_event.x < 8 * col as isize + 8 &&
                                       mouse_event.y >= 16 * row as isize &&
                                       mouse_event.y < 16 * row as isize + 16 {
                                        self.selected = i;
                                        redraw = true;
                                    }
                                    col += 1;
                                }
                            }
                            if col >= window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1;
                    }

                    if redraw {
                        self.draw_content(&mut window);
                    }
                }
                EventOption::None => sys_yield(),
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => FileManager::new().main(arg.clone()),
        Option::None => FileManager::new().main("file:///".to_string()),
    }
}
<commit_msg>Fix file manager width, it was too wide<commit_after>use redox::*;

pub struct FileManager {
    files: Vec<String>,
    selected: isize,
}

impl FileManager {
    pub fn new() -> FileManager {
        return FileManager {
            files: Vec::new(),
            selected: -1,
        };
    }

    fn draw_content(&mut self, window: &mut Window) {
        window.set([0, 0, 0, 255]);

        let mut i = 0;
        let mut row = 0;
        for string in self.files.iter() {
            let mut col = 0;
            for c in string.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    let color;
                    if i == self.selected {
                        color = [128, 128, 128, 255];
                    } else {
                        color = [255, 255, 255, 255];
                    }

                    if col < window.width() / 8 && row < window.height() / 16 {
                        window.char(8 * col as isize, 16 * row as isize, c, color);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }
            row += 1;
            i += 1;
        }

        window.sync();
    }

    fn main(&mut self, path: String) {
        let mut width = 160;
        let mut height = 0;
        {
            let mut resource = File::open(&path);

            let mut vec: Vec<u8> = Vec::new();
            resource.read_to_end(&mut vec);

            for file in String::from_utf8(&vec).split("\n".to_string()) {
                if width < (file.len() + 1) * 8 {
                    width = (file.len() + 1) * 8;
                }
                self.files.push(file);
            }

            if height < self.files.len() * 16 {
                height = self.files.len() * 16;
            }
        }

        let mut window = Window::new((rand() % 400 + 50) as isize, (rand() % 300 + 50) as isize,
                                     width, height,
                                     &("File Manager (".to_string() + &path + ")"));

        self.draw_content(&mut window);

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            K_ESC => break,
                            K_HOME => self.selected = 0,
                            K_UP => if self.selected > 0 {
                                self.selected -= 1;
                            },
                            K_END => self.selected = self.files.len() as isize - 1,
                            K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Option::Some(file) => OpenEvent {
                                                url_string: path.clone() + file.clone(),
                                            }
                                                                      .trigger(),
                                            Option::None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file[0] == key_event.character {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }

                        self.draw_content(&mut window);
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < window.width() / 8 &&
                                   row < window.height() / 16 {
                                    if mouse_event.x >= 8 * col as isize &&
                                       mouse_event.x < 8 * col as isize + 8 &&
                                       mouse_event.y >= 16 * row as isize &&
                                       mouse_event.y < 16 * row as isize + 16 {
                                        self.selected = i;
                                        redraw = true;
                                    }
                                    col += 1;
                                }
                            }
                            if col >= window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1;
                    }

                    if redraw {
                        self.draw_content(&mut window);
                    }
                }
                EventOption::None => sys_yield(),
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => FileManager::new().main(arg.clone()),
        Option::None => FileManager::new().main("file:///".to_string()),
    }
}
<|endoftext|>