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

//! The `PhilipsHueAdapter`
//!
//! This adapter implements support for Philips Hue bridges.

// Clippy complains about `hub_id` and `hub_ip` being too similar,
// suggests renaming to `hub_i_p`.
#![allow(clippy)]

pub mod discovery;
pub mod http;
pub mod hub;
pub mod hub_api;
pub mod lights;
pub mod structs;

use foxbox_core::traits::Controller;
use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::manager::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::{ format, Color, OnOff, TypeError, Value };

use std::collections::HashMap;
use std::sync::{ Arc, Mutex };
use std::thread;
use self::hub::Hub;
use self::lights::Light;
use transformable_channels::mpsc::*;

static ADAPTER_NAME: &'static str = "Philips Hue adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

/// Philips Hue Adapter's main loop handles messages of these types.
#[allow(dead_code)]
pub enum HueAction {
    TriggerDiscovery,
    AddHub(String, String),         // Hub id, hub ip
    AddLight(String, String),       // Hub id, light id
    RemoveHub(String),              // Hub id
    RemoveLight(String, String),    // Hub id, light id
    StopAdapter,
}

pub type LightServiceMap = Arc<Mutex<LightServiceMapInternal>>;

pub struct LightServiceMapInternal {
    getters: HashMap<Id<Channel>, Light>,
    setters: HashMap<Id<Channel>, Light>,
}

#[derive(Clone)]
pub struct PhilipsHueAdapter<C> {
    /// A reference to the AdapterManager.
    manager: Arc<AdapterManager>,

    controller: C,

    services: LightServiceMap,

    /// Tx channel for sending messages to the adapter's main loop.
    tx: Arc<Mutex<RawSender<HueAction>>>,

    /// The ID of this adapter (permanently fixed)
    adapter_id: Id<AdapterId>,
}

impl<C: Controller> PhilipsHueAdapter<C> {
    #[allow(dead_code)]
    pub fn init(manager: &Arc<AdapterManager>, controller: C) -> Result<(), Error> {
        let services = Arc::new(Mutex::new(LightServiceMapInternal {
            getters: HashMap::new(),
            setters: HashMap::new(),
        }));

        let (tx, rx) = channel();

        let adapter = PhilipsHueAdapter {
            manager: manager.clone(),
            controller: controller.clone(),
            services: services.clone(),
            tx: Arc::new(Mutex::new(tx.clone())),
            adapter_id: create_adapter_id(),
        };

        try!(manager.add_adapter(Arc::new(adapter.clone())));

        // Trigger discovery
        let _ = tx.send(HueAction::TriggerDiscovery);

        let manager = manager.clone();
        let services = services.clone();

        thread::spawn(move || {
            debug!("Starting Philips Hue Adapter main thread");

            let mut hubs: HashMap<String, Arc<Mutex<Hub<C>>>> = HashMap::new();
            let mut lights: HashMap<String, Arc<Mutex<Light>>> = HashMap::new();

            let discovery = discovery::Discovery::new(adapter.clone());

            'recv: for action in rx {
                match action {
                    HueAction::TriggerDiscovery => {
                        debug!("HueAction::TriggerDiscovery received");
                        discovery.do_discovery();
                    },
                    HueAction::AddHub(hub_id, hub_ip) => {
                        debug!("HueAction::AddHub({},{}) received", hub_id, hub_ip);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let mut hub = hubs.get_mut(&hub_id).unwrap().lock().unwrap();
                            hub.update_ip(&hub_ip);
                        } else {
                            let new_hub = Hub::new(adapter.clone(), &hub_id, &hub_ip);
                            new_hub.start();
                            hubs.insert(hub_id, Arc::new(Mutex::new(new_hub)));
                        }
                    },
                    HueAction::AddLight(hub_id, light_id) => {
                        debug!("HueAction::AddLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            warn!("Ignoring request to add pre-existing Hue light");
                        } else {
                            // TODO: check if hub is known
                            let hub = hubs.get(&hub_id).unwrap().lock().unwrap();
                            let mut new_light: Light = Light::new(hub.api.clone(), &hub_id,
                                &light_id);
                            let _ = new_light.init_service(manager.clone(), services.clone());
                            new_light.start();
                            lights.insert(id, Arc::new(Mutex::new(new_light)));
                        }
                    },
                    // Currently unused
                    HueAction::RemoveHub(hub_id) => {
                        debug!("HueAction::RemoveHub({}) received", hub_id);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let _ = hubs.remove(&hub_id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // Currently unused
                    HueAction::RemoveLight(hub_id, light_id) => {
                        debug!("HueAction::RemoveLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            let _ = lights.remove(&id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // TODO: Currently unused, but required for teardown
                    HueAction::StopAdapter => {
                        debug!("HueAction::StopAdapter received");
                        break;
                    },
                }
            }

            debug!("Stopping Philips Hue Adapter main thread.");

            for (_, light) in lights.drain() {
                light.lock().unwrap().stop();
            }

            for (_, hub) in hubs.drain() {
                hub.lock().unwrap().stop();
            }

        });

        Ok(())
    }

    // TODO: This should be called on tear-down by the adapter manager or
    // the taxonomy manager, but currently it can't be because the adapter
    // manager is never given a reference and .stop() is not part of a
    // trait shared amongst adapters.
    #[allow(dead_code)]
    pub fn stop(&self) {
        let _ = self.tx.lock().unwrap().send(HueAction::StopAdapter);
    }

    pub fn send(&self, action: HueAction) {
        let _ = self.tx.lock().unwrap().send(action);
    }
}

pub fn create_adapter_id() -> Id<AdapterId> {
    Id::new("philips_hue@link.mozilla.org")
}

pub fn create_light_id(hub_id: &str, light_id: &str) -> Id<ServiceId> {
    Id::new(&format!("service:{}.{}.{}", light_id, hub_id, create_adapter_id()))
}

pub fn create_channel_id(op: &str, hub_id: &str, light_id: &str) -> Id<Channel> {
    Id::new(&format!("channel:{}.{}.{}.{}", op, light_id, hub_id, create_adapter_id()))
}

impl<C: Controller> Adapter for PhilipsHueAdapter<C> {
    fn id(&self) -> Id<AdapterId> {
        create_adapter_id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32; 4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User)
        -> ResultMap<Id<Channel>, Option<Value>, Error>
    {
        set.drain(..).map(|id| {
            let light = match self.services.lock().unwrap().getters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.get_available_id {
                if light.get_available() {
                    return (id, Ok(Some(Value::OnOff(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::OnOff(OnOff::Off))));
                }
            }
            if id == light.channel_power_id {
                if light.get_power() {
                    return (id, Ok(Some(Value::OnOff(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::OnOff(OnOff::Off))));
                }
            }
            if id == light.channel_color_id {
                let (h, s, v) = light.get_color();
                return (id, Ok(Some(Value::Color(Color::HSV(h, s, v)))));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, _: User)
        -> ResultMap<Id<Channel>, (), Error>
    {
        values.drain().map(|(id, value)| {
            let light = match self.services.lock().unwrap().setters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.channel_power_id {
                match value {
                    Value::OnOff(OnOff::On)  => { light.set_power(true); },
                    Value::OnOff(OnOff::Off) => { light.set_power(false); },
                    _ => {
                        return (id, Err(Error::TypeError(TypeError::new(&format::ON_OFF, &value))));
                    }
                }
                return (id, Ok(()));
            }
            if id == light.channel_color_id {
                match value {
                    Value::Color(Color::HSV(h, s, v)) => { light.set_color((h, s, v)); },
                    _ => {
                        return (id, Err(Error::TypeError(TypeError::new(&format::COLOR, &value) )));
                    }
                }
                return (id, Ok(()));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }
}
<commit_msg>Hue: Getting rid of centralized Value<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The `PhilipsHueAdapter`
//!
//! This adapter implements support for Philips Hue bridges.

// Clippy complains about `hub_id` and `hub_ip` being too similar,
// suggests renaming to `hub_i_p`.
#![allow(clippy)]

pub mod discovery;
pub mod http;
pub mod hub;
pub mod hub_api;
pub mod lights;
pub mod structs;

use foxbox_core::traits::Controller;
use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::manager::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::{ Color, OnOff, Value };

use std::collections::HashMap;
use std::sync::{ Arc, Mutex };
use std::thread;
use self::hub::Hub;
use self::lights::Light;
use transformable_channels::mpsc::*;

static ADAPTER_NAME: &'static str = "Philips Hue adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

/// Philips Hue Adapter's main loop handles messages of these types.
#[allow(dead_code)]
pub enum HueAction {
    TriggerDiscovery,
    AddHub(String, String),         // Hub id, hub ip
    AddLight(String, String),       // Hub id, light id
    RemoveHub(String),              // Hub id
    RemoveLight(String, String),    // Hub id, light id
    StopAdapter,
}

pub type LightServiceMap = Arc<Mutex<LightServiceMapInternal>>;

pub struct LightServiceMapInternal {
    getters: HashMap<Id<Channel>, Light>,
    setters: HashMap<Id<Channel>, Light>,
}

#[derive(Clone)]
pub struct PhilipsHueAdapter<C> {
    /// A reference to the AdapterManager.
    manager: Arc<AdapterManager>,

    controller: C,

    services: LightServiceMap,

    /// Tx channel for sending messages to the adapter's main loop.
    tx: Arc<Mutex<RawSender<HueAction>>>,

    /// The ID of this adapter (permanently fixed)
    adapter_id: Id<AdapterId>,
}

impl<C: Controller> PhilipsHueAdapter<C> {
    #[allow(dead_code)]
    pub fn init(manager: &Arc<AdapterManager>, controller: C) -> Result<(), Error> {
        let services = Arc::new(Mutex::new(LightServiceMapInternal {
            getters: HashMap::new(),
            setters: HashMap::new(),
        }));

        let (tx, rx) = channel();

        let adapter = PhilipsHueAdapter {
            manager: manager.clone(),
            controller: controller.clone(),
            services: services.clone(),
            tx: Arc::new(Mutex::new(tx.clone())),
            adapter_id: create_adapter_id(),
        };

        try!(manager.add_adapter(Arc::new(adapter.clone())));

        // Trigger discovery
        let _ = tx.send(HueAction::TriggerDiscovery);

        let manager = manager.clone();
        let services = services.clone();

        thread::spawn(move || {
            debug!("Starting Philips Hue Adapter main thread");

            let mut hubs: HashMap<String, Arc<Mutex<Hub<C>>>> = HashMap::new();
            let mut lights: HashMap<String, Arc<Mutex<Light>>> = HashMap::new();

            let discovery = discovery::Discovery::new(adapter.clone());

            'recv: for action in rx {
                match action {
                    HueAction::TriggerDiscovery => {
                        debug!("HueAction::TriggerDiscovery received");
                        discovery.do_discovery();
                    },
                    HueAction::AddHub(hub_id, hub_ip) => {
                        debug!("HueAction::AddHub({},{}) received", hub_id, hub_ip);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let mut hub = hubs.get_mut(&hub_id).unwrap().lock().unwrap();
                            hub.update_ip(&hub_ip);
                        } else {
                            let new_hub = Hub::new(adapter.clone(), &hub_id, &hub_ip);
                            new_hub.start();
                            hubs.insert(hub_id, Arc::new(Mutex::new(new_hub)));
                        }
                    },
                    HueAction::AddLight(hub_id, light_id) => {
                        debug!("HueAction::AddLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            warn!("Ignoring request to add pre-existing Hue light");
                        } else {
                            // TODO: check if hub is known
                            let hub = hubs.get(&hub_id).unwrap().lock().unwrap();
                            let mut new_light: Light = Light::new(hub.api.clone(), &hub_id,
                                &light_id);
                            let _ = new_light.init_service(manager.clone(), services.clone());
                            new_light.start();
                            lights.insert(id, Arc::new(Mutex::new(new_light)));
                        }
                    },
                    // Currently unused
                    HueAction::RemoveHub(hub_id) => {
                        debug!("HueAction::RemoveHub({}) received", hub_id);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let _ = hubs.remove(&hub_id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // Currently unused
                    HueAction::RemoveLight(hub_id, light_id) => {
                        debug!("HueAction::RemoveLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            let _ = lights.remove(&id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // TODO: Currently unused, but required for teardown
                    HueAction::StopAdapter => {
                        debug!("HueAction::StopAdapter received");
                        break;
                    },
                }
            }

            debug!("Stopping Philips Hue Adapter main thread.");

            for (_, light) in lights.drain() {
                light.lock().unwrap().stop();
            }

            for (_, hub) in hubs.drain() {
                hub.lock().unwrap().stop();
            }

        });

        Ok(())
    }

    // TODO: This should be called on tear-down by the adapter manager or
    // the taxonomy manager, but currently it can't be because the adapter
    // manager is never given a reference and .stop() is not part of a
    // trait shared amongst adapters.
    #[allow(dead_code)]
    pub fn stop(&self) {
        let _ = self.tx.lock().unwrap().send(HueAction::StopAdapter);
    }

    pub fn send(&self, action: HueAction) {
        let _ = self.tx.lock().unwrap().send(action);
    }
}

pub fn create_adapter_id() -> Id<AdapterId> {
    Id::new("philips_hue@link.mozilla.org")
}

pub fn create_light_id(hub_id: &str, light_id: &str) -> Id<ServiceId> {
    Id::new(&format!("service:{}.{}.{}", light_id, hub_id, create_adapter_id()))
}

pub fn create_channel_id(op: &str, hub_id: &str, light_id: &str) -> Id<Channel> {
    Id::new(&format!("channel:{}.{}.{}.{}", op, light_id, hub_id, create_adapter_id()))
}

impl<C: Controller> Adapter for PhilipsHueAdapter<C> {
    fn id(&self) -> Id<AdapterId> {
        create_adapter_id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32; 4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User)
        -> ResultMap<Id<Channel>, Option<Value>, Error>
    {
        set.drain(..).map(|id| {
            let light = match self.services.lock().unwrap().getters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.get_available_id {
                if light.get_available() {
                    return (id, Ok(Some(Value::new(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::new(OnOff::Off))));
                }
            }
            if id == light.channel_power_id {
                if light.get_power() {
                    return (id, Ok(Some(Value::new(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::new(OnOff::Off))));
                }
            }
            if id == light.channel_color_id {
                let (h, s, v) = light.get_color();
                return (id, Ok(Some(Value::new(Color::HSV(h, s, v)))));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, _: User)
        -> ResultMap<Id<Channel>, (), Error>
    {
        values.drain().map(|(id, value)| {
            let light = match self.services.lock().unwrap().setters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.channel_power_id {
                match value.cast::<OnOff>() {
                    Ok(&OnOff::On)  => { light.set_power(true); },
                    Ok(&OnOff::Off) => { light.set_power(false); },
                    Err(err) => return (id, Err(err))
                }
                return (id, Ok(()));
            }
            if id == light.channel_color_id {
                match value.cast::<Color>() {
                    Ok(&Color::HSV(ref h, ref s, ref v)) => { light.set_color((h.clone(), s.clone(), v.clone())); },
                    Err(err) => return (id, Err(err))
                }
                return (id, Ok(()));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }
}
<|endoftext|>


<commit_before>use crate::util::errors::CargoResult;
use std::hash::{self, Hash};
use url::Url;

/// A newtype wrapper around `Url` which represents a "canonical" version of an
/// original URL.
///
/// A "canonical" url is only intended for internal comparison purposes in
/// Cargo. It's to help paper over mistakes such as depending on
/// `github.com/foo/bar` vs `github.com/foo/bar.git`. This is **only** for
/// internal purposes within Cargo and provides no means to actually read the
/// underlying string value of the `Url` it contains. This is intentional,
/// because all fetching should still happen within the context of the original
/// URL.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct CanonicalUrl(Url);

impl CanonicalUrl {
    pub fn new(url: &Url) -> CargoResult<CanonicalUrl> {
        let mut url = url.clone();

        // cannot-be-a-base-urls (e.g., `github.com:rust-lang-nursery/rustfmt.git`)
        // are not supported.
        if url.cannot_be_a_base() {
            anyhow::bail!(
                "invalid url `{}`: cannot-be-a-base-URLs are not supported",
                url
            )
        }

        // Strip a trailing slash.
        if url.path().ends_with('/') {
            url.path_segments_mut().unwrap().pop_if_empty();
        }

        // For GitHub URLs specifically, just lower-case everything. GitHub
        // treats both the same, but they hash differently, and we're gonna be
        // hashing them. This wants a more general solution, and also we're
        // almost certainly not using the same case conversion rules that GitHub
        // does. (See issue #84)
        if url.host_str() == Some("github.com") {
            url.set_scheme("https").unwrap();
            let path = url.path().to_lowercase();
            url.set_path(&path);
        }

        // Repos can generally be accessed with or without `.git` extension.
        let needs_chopping = url.path().ends_with(".git");
        if needs_chopping {
            let last = {
                let last = url.path_segments().unwrap().next_back().unwrap();
                last[..last.len() - 4].to_owned()
            };
            url.path_segments_mut().unwrap().pop().push(&last);
        }

        Ok(CanonicalUrl(url))
    }

    /// Returns the raw canonicalized URL, although beware that this should
    /// never be used/displayed/etc, it should only be used for internal data
    /// structures and hashes and such.
    pub fn raw_canonicalized_url(&self) -> &Url {
        &self.0
    }
}

// See comment in `source_id.rs` for why we explicitly use `as_str()` here.
impl Hash for CanonicalUrl {
    fn hash<S: hash::Hasher>(&self, into: &mut S) {
        self.0.as_str().hash(into);
    }
}
<commit_msg>Fix tests with `url` crate update<commit_after>use crate::util::errors::CargoResult;
use std::hash::{self, Hash};
use url::Url;

/// A newtype wrapper around `Url` which represents a "canonical" version of an
/// original URL.
///
/// A "canonical" url is only intended for internal comparison purposes in
/// Cargo. It's to help paper over mistakes such as depending on
/// `github.com/foo/bar` vs `github.com/foo/bar.git`. This is **only** for
/// internal purposes within Cargo and provides no means to actually read the
/// underlying string value of the `Url` it contains. This is intentional,
/// because all fetching should still happen within the context of the original
/// URL.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct CanonicalUrl(Url);

impl CanonicalUrl {
    pub fn new(url: &Url) -> CargoResult<CanonicalUrl> {
        let mut url = url.clone();

        // cannot-be-a-base-urls (e.g., `github.com:rust-lang-nursery/rustfmt.git`)
        // are not supported.
        if url.cannot_be_a_base() {
            anyhow::bail!(
                "invalid url `{}`: cannot-be-a-base-URLs are not supported",
                url
            )
        }

        // Strip a trailing slash.
        if url.path().ends_with('/') {
            url.path_segments_mut().unwrap().pop_if_empty();
        }

        // For GitHub URLs specifically, just lower-case everything. GitHub
        // treats both the same, but they hash differently, and we're gonna be
        // hashing them. This wants a more general solution, and also we're
        // almost certainly not using the same case conversion rules that GitHub
        // does. (See issue #84)
        if url.host_str() == Some("github.com") {
            url = format!("https{}", &url[url::Position::AfterScheme..])
                .parse()
                .unwrap();
            let path = url.path().to_lowercase();
            url.set_path(&path);
        }

        // Repos can generally be accessed with or without `.git` extension.
        let needs_chopping = url.path().ends_with(".git");
        if needs_chopping {
            let last = {
                let last = url.path_segments().unwrap().next_back().unwrap();
                last[..last.len() - 4].to_owned()
            };
            url.path_segments_mut().unwrap().pop().push(&last);
        }

        Ok(CanonicalUrl(url))
    }

    /// Returns the raw canonicalized URL, although beware that this should
    /// never be used/displayed/etc, it should only be used for internal data
    /// structures and hashes and such.
    pub fn raw_canonicalized_url(&self) -> &Url {
        &self.0
    }
}

// See comment in `source_id.rs` for why we explicitly use `as_str()` here.
impl Hash for CanonicalUrl {
    fn hash<S: hash::Hasher>(&self, into: &mut S) {
        self.0.as_str().hash(into);
    }
}
<|endoftext|>


<commit_before>// This is an X-Macro.
#[macro_export]
macro_rules! list_of_all_specifier_classes {
    ($your_macro:ident) => {
        $your_macro!($crate::ws_client_peer::WsClientClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ws_client_peer::WsClientSecureClass);
        $your_macro!($crate::ws_server_peer::WsTcpServerClass);
        $your_macro!($crate::ws_server_peer::WsInetdServerClass);
        $your_macro!($crate::ws_server_peer::WsUnixServerClass);
        $your_macro!($crate::ws_server_peer::WsAbstractUnixServerClass);
        $your_macro!($crate::ws_server_peer::WsServerClass);

        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsConnectClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsAcceptClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsListenClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::WssListenClass);

        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::StdioClass);
        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::InetdClass);
        #[cfg(not(all(unix, feature = "unix_stdio")))]
        $your_macro!($crate::stdio_threaded_peer::ThreadedStdioSubstituteClass);
        #[cfg(not(all(unix, feature = "unix_stdio")))]
        $your_macro!($crate::stdio_threaded_peer::InetdClass);

        $your_macro!($crate::net_peer::TcpConnectClass);
        $your_macro!($crate::net_peer::TcpListenClass);

        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::ShCClass);
        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::CmdClass);
        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::ExecClass);

        $your_macro!($crate::file_peer::ReadFileClass);
        $your_macro!($crate::file_peer::WriteFileClass);
        $your_macro!($crate::file_peer::AppendFileClass);

        $your_macro!($crate::primitive_reuse_peer::ReuserClass);
        $your_macro!($crate::broadcast_reuse_peer::BroadcastReuserClass);
        $your_macro!($crate::reconnect_peer::AutoReconnectClass);

        $your_macro!($crate::ws_client_peer::WsConnectClass);

        $your_macro!($crate::net_peer::UdpConnectClass);
        $your_macro!($crate::net_peer::UdpListenClass);

        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::OpenAsyncClass);
        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::OpenFdAsyncClass);

        $your_macro!($crate::stdio_threaded_peer::ThreadedStdioClass);

        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixConnectClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixListenClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixDgramClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractConnectClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractListenClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractDgramClass);

        $your_macro!($crate::line_peer::Message2LineClass);
        $your_macro!($crate::line_peer::Line2MessageClass);
        $your_macro!($crate::mirror_peer::MirrorClass);
        $your_macro!($crate::mirror_peer::LiteralReplyClass);
        $your_macro!($crate::trivial_peer::CloggedClass);
        $your_macro!($crate::trivial_peer::LiteralClass);
        $your_macro!($crate::trivial_peer::AssertClass);
        $your_macro!($crate::trivial_peer::Assert2Class);

        #[cfg(all(target_os = "linux", feature = "seqpacket"))]
        $your_macro!($crate::unix_peer::unix_seqpacket_peer::SeqpacketConnectClass);
        #[cfg(all(target_os = "linux", feature = "seqpacket"))]
        $your_macro!($crate::unix_peer::unix_seqpacket_peer::SeqpacketListenClass);

        $your_macro!($crate::jsonrpc_peer::JsonRpcClass);

        $your_macro!($crate::proxy_peer::SocksProxyClass);
        $your_macro!($crate::proxy_peer::SocksBindClass);
    };
}
<commit_msg>Reorder peers a bit<commit_after>// This is an X-Macro.
#[macro_export]
macro_rules! list_of_all_specifier_classes {
    ($your_macro:ident) => {
        $your_macro!($crate::ws_client_peer::WsClientClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ws_client_peer::WsClientSecureClass);
        $your_macro!($crate::ws_server_peer::WsTcpServerClass);
        $your_macro!($crate::ws_server_peer::WsInetdServerClass);
        $your_macro!($crate::ws_server_peer::WsUnixServerClass);
        $your_macro!($crate::ws_server_peer::WsAbstractUnixServerClass);
        $your_macro!($crate::ws_server_peer::WsServerClass);

        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::WssListenClass);

        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::StdioClass);
        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::InetdClass);
        #[cfg(not(all(unix, feature = "unix_stdio")))]
        $your_macro!($crate::stdio_threaded_peer::ThreadedStdioSubstituteClass);
        #[cfg(not(all(unix, feature = "unix_stdio")))]
        $your_macro!($crate::stdio_threaded_peer::InetdClass);

        $your_macro!($crate::net_peer::TcpConnectClass);
        $your_macro!($crate::net_peer::TcpListenClass);

        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsConnectClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsAcceptClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsListenClass);

        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::ShCClass);
        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::CmdClass);
        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::ExecClass);

        $your_macro!($crate::file_peer::ReadFileClass);
        $your_macro!($crate::file_peer::WriteFileClass);
        $your_macro!($crate::file_peer::AppendFileClass);

        $your_macro!($crate::primitive_reuse_peer::ReuserClass);
        $your_macro!($crate::broadcast_reuse_peer::BroadcastReuserClass);
        $your_macro!($crate::reconnect_peer::AutoReconnectClass);

        $your_macro!($crate::ws_client_peer::WsConnectClass);

        $your_macro!($crate::net_peer::UdpConnectClass);
        $your_macro!($crate::net_peer::UdpListenClass);

        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::OpenAsyncClass);
        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::OpenFdAsyncClass);

        $your_macro!($crate::stdio_threaded_peer::ThreadedStdioClass);

        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixConnectClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixListenClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixDgramClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractConnectClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractListenClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractDgramClass);

        $your_macro!($crate::line_peer::Message2LineClass);
        $your_macro!($crate::line_peer::Line2MessageClass);
        $your_macro!($crate::mirror_peer::MirrorClass);
        $your_macro!($crate::mirror_peer::LiteralReplyClass);
        $your_macro!($crate::trivial_peer::CloggedClass);
        $your_macro!($crate::trivial_peer::LiteralClass);
        $your_macro!($crate::trivial_peer::AssertClass);
        $your_macro!($crate::trivial_peer::Assert2Class);

        #[cfg(all(target_os = "linux", feature = "seqpacket"))]
        $your_macro!($crate::unix_peer::unix_seqpacket_peer::SeqpacketConnectClass);
        #[cfg(all(target_os = "linux", feature = "seqpacket"))]
        $your_macro!($crate::unix_peer::unix_seqpacket_peer::SeqpacketListenClass);

        $your_macro!($crate::jsonrpc_peer::JsonRpcClass);

        $your_macro!($crate::proxy_peer::SocksProxyClass);
        $your_macro!($crate::proxy_peer::SocksBindClass);
    };
}
<|endoftext|>


<commit_before>#![crate_id = "ansi_term#0.1dev"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![desc = "A rust library for ANSI terminal colours and styles (bold, underline)"]

#![feature(phase)] extern crate regex;
#[phase(plugin)] extern crate regex_macros;

pub enum Colour {
    Black, Red, Green, Yellow, Blue, Purple, Cyan, White, Fixed(u8),
}

// These are the standard numeric sequences.
// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html

impl Colour {
    fn foreground_code(&self) -> String {
        match *self {
            Black => "30".to_string(),
            Red => "31".to_string(),
            Green => "32".to_string(),
            Yellow => "33".to_string(),
            Blue => "34".to_string(),
            Purple => "35".to_string(),
            Cyan => "36".to_string(),
            White => "37".to_string(),
            Fixed(num) => format!("38;5;{}", num),
        }
    }

    fn background_code(&self) -> String {
        match *self {
            Black => "40".to_string(),
            Red => "41".to_string(),
            Green => "42".to_string(),
            Yellow => "43".to_string(),
            Blue => "44".to_string(),
            Purple => "45".to_string(),
            Cyan => "46".to_string(),
            White => "47".to_string(),
            Fixed(num) => format!("48;5;{}", num),
        }
    }
}

// There are only three different styles: plain (no formatting), only
// a foreground colour, and a catch-all for anything more complicated
// than that. It's technically possible to write other cases such as
// "bold foreground", but probably isn't worth writing all the code.

pub enum Style {
    Plain,
    Foreground(Colour),
    Style(StyleStruct),
}

// Having a struct inside an enum is currently unfinished in Rust, but
// should be put in there when that feature is complete.

pub struct StyleStruct {
    foreground: Colour,
    background: Option<Colour>,
    bold: bool,
    underline: bool,
}

impl Style {
    pub fn paint(&self, input: &str) -> String {
        match *self {
            Plain => input.to_string(),
            Foreground(c) => c.paint(input),
            Style(s) => match s {
                StyleStruct { foreground, background, bold, underline } => {
                    let bg = match background {
                        Some(c) => format!("{};", c.background_code()),
                        None => "".to_string()
                    };
                    let bo = if bold { "1;" } else { "" };
                    let un = if underline { "4;" } else { "" };
                    let painted = format!("\x1B[{}{}{}{}m{}\x1B[0m", bo, un, bg, foreground.foreground_code(), input.to_string());
                    return painted.to_string();
                }
            }
        }
    }
}

impl Style {
    pub fn bold(&self) -> Style {
        match *self {
            Plain => Style(StyleStruct         { foreground: White,         background: None,          bold: true, underline: false }),
            Foreground(c) => Style(StyleStruct { foreground: c,             background: None,          bold: true, underline: false }),
            Style(st) => Style(StyleStruct     { foreground: st.foreground, background: st.background, bold: true, underline: st.underline }),
        }
    }

    pub fn underline(&self) -> Style {
        match *self {
            Plain => Style(StyleStruct         { foreground: White,         background: None,          bold: false,   underline: true }),
            Foreground(c) => Style(StyleStruct { foreground: c,             background: None,          bold: false,   underline: true }),
            Style(st) => Style(StyleStruct     { foreground: st.foreground, background: st.background, bold: st.bold, underline: true }),
        }
    }

    pub fn on(&self, background: Colour) -> Style {
        match *self {
            Plain => Style(StyleStruct         { foreground: White,         background: Some(background), bold: false,   underline: false }),
            Foreground(c) => Style(StyleStruct { foreground: c,             background: Some(background), bold: false,   underline: false }),
            Style(st) => Style(StyleStruct     { foreground: st.foreground, background: Some(background), bold: st.bold, underline: st.underline }),
        }
    }
}

impl Colour {
    // This is a short-cut so you don't have to use Blue.normal() just
    // to turn Blue into a Style. Annoyingly, this means that Blue and
    // Blue.normal() aren't of the same type, but this hasn't been an
    // issue so far.

    pub fn paint(&self, input: &str) -> String {
        let re = format!("\x1B[{}m{}\x1B[0m", self.foreground_code(), input);
        return re.to_string();
    }

    pub fn underline(&self) -> Style {
        Style(StyleStruct { foreground: *self, background: None, bold: false, underline: true })
    }

    pub fn bold(&self) -> Style {
        Style(StyleStruct { foreground: *self, background: None, bold: true, underline: false })
    }

    pub fn normal(&self) -> Style {
        Style(StyleStruct { foreground: *self, background: None, bold: false, underline: false })
    }

    pub fn on(&self, background: Colour) -> Style {
        Style(StyleStruct { foreground: *self, background: Some(background), bold: false, underline: false })
    }
}

pub fn strip_formatting(input: String) -> String {
    let re = regex!("\x1B\\[.+?m");
    re.replace_all(input.as_slice(), "").to_string()
}

#[cfg(test)]
mod tests {
    use super::{Black, Red, Green, Yellow, Blue, Purple, Cyan, White, Fixed, Plain, strip_formatting};

    #[test]
    fn test_plain() {
        let hi = Plain.paint("text/plain");
        assert!(hi == "text/plain".to_string());
    }

    #[test]
    fn test_red() {
        let hi = Red.paint("hi");
        assert!(hi == "\x1B[31mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_black() {
        let hi = Black.normal().paint("hi");
        assert!(hi == "\x1B[30mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_yellow_bold() {
        let hi = Yellow.bold().paint("hi");
        assert!(hi == "\x1B[1;33mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_yellow_bold_2() {
        let hi = Yellow.normal().bold().paint("hi");
        assert!(hi == "\x1B[1;33mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_blue_underline() {
        let hi = Blue.underline().paint("hi");
        assert!(hi == "\x1B[4;34mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_green_bold_underline() {
        let hi = Green.bold().underline().paint("hi");
        assert!(hi == "\x1B[1;4;32mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_green_bold_underline_2() {
        let hi = Green.underline().bold().paint("hi");
        assert!(hi == "\x1B[1;4;32mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_purple_on_white() {
        let hi = Purple.on(White).paint("hi");
        assert!(hi == "\x1B[47;35mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_purple_on_white_2() {
        let hi = Purple.normal().on(White).paint("hi");
        assert!(hi == "\x1B[47;35mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_bold_on_white() {
        let hi = Cyan.bold().on(White).paint("hi");
        assert!(hi == "\x1B[1;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_underline_on_white() {
        let hi = Cyan.underline().on(White).paint("hi");
        assert!(hi == "\x1B[4;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_bold_underline_on_white() {
        let hi = Cyan.bold().underline().on(White).paint("hi");
        assert!(hi == "\x1B[1;4;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_underline_bold_on_white() {
        let hi = Cyan.underline().bold().on(White).paint("hi");
        assert!(hi == "\x1B[1;4;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_fixed() {
        let hi = Fixed(100).paint("hi");
        assert!(hi == "\x1B[38;5;100mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_fixed_on_purple() {
        let hi = Fixed(100).on(Purple).paint("hi");
        assert!(hi == "\x1B[45;38;5;100mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_fixed_on_fixed() {
        let hi = Fixed(100).on(Fixed(200)).paint("hi");
        assert!(hi == "\x1B[48;5;200;38;5;100mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_strip_formatting() {
        let hi = strip_formatting(Blue.paint("hi"));
        assert!(hi == "hi".to_string());
    }

    #[test]
    fn test_strip_formatting_2() {
        let hi = strip_formatting(Blue.on(Fixed(230)).bold().paint("hi"));
        assert!(hi == "hi".to_string());
    }
}
<commit_msg>Add rustdoc comments<commit_after>#![crate_id = "ansi_term#0.1dev"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![desc = "A rust library for ANSI terminal colours and styles (bold, underline)"]

//! This is a library for controlling colours and formatting, such as
//! red bold text or blue underlined text, on ANSI terminals.
//!
//! Simple Colours
//! --------------
//!
//! You can format strings by calling the `paint` method on a Colour
//! or a Style object, passing in the string you want to format. For
//! example, to get some red text, call the `paint` method on `Red`:
//!
//! ```rust
//! Red.paint("Red!")
//! ```
//!
//! You can also call the `paint` method on a Style. To turn a Colour
//! into a Style, use the `normal` method, though this does the exact
//! some thing as above:
//!
//! ```rust
//! Red.normal().paint("Still red!")
//! ```
//!
//! Bold, Underline, and Background
//! -------------------------------
//!
//! To do anything more complex than just foreground colours, you need
//! to use Style objects. Calling the `bold` or `underline` method on
//! a Colour returns a Style that has the appropriate property set on
//! it:
//!
//! ```rust
//! Blue.bold().paint("Blue bold!")
//! Yellow.underline().paint("Yellow underline!")
//! ```
//!
//! Again, you can call these methods on Styles as well as just Colours:
//!
//! ```rust
//! Blue.normal().bold().paint("Still blue bold!")
//! ```
//!
//! Finally, you can set the background colour of a Style by using the
//! `on` method:
//!
//! ```rust
//! Blue.on(Yellow).paint("Blue on yellow!")
//! ```
//!
//! Extended Colours
//! ----------------
//!
//! You can access the extended range of 256 colours by using the
//! Fixed constructor, which takes an argument of the colour number to
//! use. This can be used wherever you would use a Colour:
//!
//! ```rust
//! Fixed(134).paint("A sort of light purple.")
//! ```
//!
//! This even works for background colours:
//!
//! ```rust
//! Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup.")
//! ```
//!
//! No Formatting
//! -------------
//!
//! Finally, for the sake of completeness, the Plain style provides
//! neither colours nor formatting.
//!
//! ```rust
//! Plain.paint("No colours here.")
//! ```

#![feature(phase)] extern crate regex;
#[phase(plugin)] extern crate regex_macros;

/// A colour is one specific type of ANSI escape code, and can refer
/// to either the foreground or background colour.
pub enum Colour {
    Black, Red, Green, Yellow, Blue, Purple, Cyan, White, Fixed(u8),
}

// These are the standard numeric sequences.
// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html

impl Colour {
    fn foreground_code(&self) -> String {
        match *self {
            Black => "30".to_string(),
            Red => "31".to_string(),
            Green => "32".to_string(),
            Yellow => "33".to_string(),
            Blue => "34".to_string(),
            Purple => "35".to_string(),
            Cyan => "36".to_string(),
            White => "37".to_string(),
            Fixed(num) => format!("38;5;{}", num),
        }
    }

    fn background_code(&self) -> String {
        match *self {
            Black => "40".to_string(),
            Red => "41".to_string(),
            Green => "42".to_string(),
            Yellow => "43".to_string(),
            Blue => "44".to_string(),
            Purple => "45".to_string(),
            Cyan => "46".to_string(),
            White => "47".to_string(),
            Fixed(num) => format!("48;5;{}", num),
        }
    }
}

/// A style is a collection of properties that can format a string
/// using ANSI escape codes.
pub enum Style {
    /// The Plain style provides no formatting.
    Plain,
    /// The Foreground style provides just a foreground colour.
    Foreground(Colour),
    /// The Style style is a catch-all for anything more complicated
    /// than that. It's technically possible for there to be other
    /// cases, such as "bold foreground", but probably isn't worth it.
    Style(StyleStruct),
}

// Having a struct inside an enum is currently unfinished in Rust, but
// should be put in there when that feature is complete.

struct StyleStruct {
    foreground: Colour,
    background: Option<Colour>,
    bold: bool,
    underline: bool,
}

impl Style {
    /// Paints the given text with this style, returning a String of
    /// text with the relevant ANSI escape codes added.
    pub fn paint(&self, input: &str) -> String {
        match *self {
            Plain => input.to_string(),
            Foreground(c) => c.paint(input),
            Style(s) => match s {
                StyleStruct { foreground, background, bold, underline } => {
                    let bg = match background {
                        Some(c) => format!("{};", c.background_code()),
                        None => "".to_string()
                    };
                    let bo = if bold { "1;" } else { "" };
                    let un = if underline { "4;" } else { "" };
                    let painted = format!("\x1B[{}{}{}{}m{}\x1B[0m", bo, un, bg, foreground.foreground_code(), input.to_string());
                    return painted.to_string();
                }
            }
        }
    }

    /// Return a Style with the bold property set.
    pub fn bold(&self) -> Style {
        match *self {
            Plain => Style(StyleStruct         { foreground: White,         background: None,          bold: true, underline: false }),
            Foreground(c) => Style(StyleStruct { foreground: c,             background: None,          bold: true, underline: false }),
            Style(st) => Style(StyleStruct     { foreground: st.foreground, background: st.background, bold: true, underline: st.underline }),
        }
    }

    /// Return a Style with the underline property set.
    pub fn underline(&self) -> Style {
        match *self {
            Plain => Style(StyleStruct         { foreground: White,         background: None,          bold: false,   underline: true }),
            Foreground(c) => Style(StyleStruct { foreground: c,             background: None,          bold: false,   underline: true }),
            Style(st) => Style(StyleStruct     { foreground: st.foreground, background: st.background, bold: st.bold, underline: true }),
        }
    }

    /// Return a Style with the background colour set.
    pub fn on(&self, background: Colour) -> Style {
        match *self {
            Plain => Style(StyleStruct         { foreground: White,         background: Some(background), bold: false,   underline: false }),
            Foreground(c) => Style(StyleStruct { foreground: c,             background: Some(background), bold: false,   underline: false }),
            Style(st) => Style(StyleStruct     { foreground: st.foreground, background: Some(background), bold: st.bold, underline: st.underline }),
        }
    }
}

impl Colour {
    /// Paints the given text with this colour. This is a short-cut so
    /// you don't have to use Blue.normal() just to get blue text.
    pub fn paint(&self, input: &str) -> String {
        let re = format!("\x1B[{}m{}\x1B[0m", self.foreground_code(), input);
        return re.to_string();
    }

    /// Returns a Style with the underline property set.
    pub fn underline(&self) -> Style {
        Style(StyleStruct { foreground: *self, background: None, bold: false, underline: true })
    }

    /// Return a Style with the bold property set.
    pub fn bold(&self) -> Style {
        Style(StyleStruct { foreground: *self, background: None, bold: true, underline: false })
    }

    /// Return a Style with the foreground colour set to this colour.
    pub fn normal(&self) -> Style {
        Style(StyleStruct { foreground: *self, background: None, bold: false, underline: false })
    }

    /// Return a Style with the background colour set.
    pub fn on(&self, background: Colour) -> Style {
        Style(StyleStruct { foreground: *self, background: Some(background), bold: false, underline: false })
    }
}

/// Return a String with all ANSI escape codes removed. For example:
///
/// ```rust
/// strip_formatting(Blue.paint("hello!")) == "hello!"
/// ```
pub fn strip_formatting(input: String) -> String {
    // What's blue and smells like red paint? Blue paint.
    let re = regex!("\x1B\\[.+?m");
    re.replace_all(input.as_slice(), "").to_string()
}

#[cfg(test)]
mod tests {
    use super::{Black, Red, Green, Yellow, Blue, Purple, Cyan, White, Fixed, Plain, strip_formatting};

    #[test]
    fn test_plain() {
        let hi = Plain.paint("text/plain");
        assert!(hi == "text/plain".to_string());
    }

    #[test]
    fn test_red() {
        let hi = Red.paint("hi");
        assert!(hi == "\x1B[31mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_black() {
        let hi = Black.normal().paint("hi");
        assert!(hi == "\x1B[30mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_yellow_bold() {
        let hi = Yellow.bold().paint("hi");
        assert!(hi == "\x1B[1;33mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_yellow_bold_2() {
        let hi = Yellow.normal().bold().paint("hi");
        assert!(hi == "\x1B[1;33mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_blue_underline() {
        let hi = Blue.underline().paint("hi");
        assert!(hi == "\x1B[4;34mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_green_bold_underline() {
        let hi = Green.bold().underline().paint("hi");
        assert!(hi == "\x1B[1;4;32mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_green_bold_underline_2() {
        let hi = Green.underline().bold().paint("hi");
        assert!(hi == "\x1B[1;4;32mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_purple_on_white() {
        let hi = Purple.on(White).paint("hi");
        assert!(hi == "\x1B[47;35mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_purple_on_white_2() {
        let hi = Purple.normal().on(White).paint("hi");
        assert!(hi == "\x1B[47;35mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_bold_on_white() {
        let hi = Cyan.bold().on(White).paint("hi");
        assert!(hi == "\x1B[1;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_underline_on_white() {
        let hi = Cyan.underline().on(White).paint("hi");
        assert!(hi == "\x1B[4;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_bold_underline_on_white() {
        let hi = Cyan.bold().underline().on(White).paint("hi");
        assert!(hi == "\x1B[1;4;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_cyan_underline_bold_on_white() {
        let hi = Cyan.underline().bold().on(White).paint("hi");
        assert!(hi == "\x1B[1;4;47;36mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_fixed() {
        let hi = Fixed(100).paint("hi");
        assert!(hi == "\x1B[38;5;100mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_fixed_on_purple() {
        let hi = Fixed(100).on(Purple).paint("hi");
        assert!(hi == "\x1B[45;38;5;100mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_fixed_on_fixed() {
        let hi = Fixed(100).on(Fixed(200)).paint("hi");
        assert!(hi == "\x1B[48;5;200;38;5;100mhi\x1B[0m".to_string());
    }

    #[test]
    fn test_strip_formatting() {
        let hi = strip_formatting(Blue.paint("hi"));
        assert!(hi == "hi".to_string());
    }

    #[test]
    fn test_strip_formatting_2() {
        let hi = strip_formatting(Blue.on(Fixed(230)).bold().paint("hi"));
        assert!(hi == "hi".to_string());
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use toml;

#[derive(Debug, RustcDecodable)]
pub struct ModuleOpts {
    meta: MetaOpts,
    options: OptionsOpts
}

impl ModuleOpts {
    pub fn load(path: String) -> Result<ModuleOpts, &'static str> {
        let mut mod_string = String::new();
        let mut file = match File::open(&path) {
            Ok(file) => file,
            Err(_) => {
                return Err("Could not load config file")
            }
        };
        file.read_to_string(&mut mod_string)
        .unwrap_or_else(|e| panic!("Unrecoverable error while reading config: {}", e));

        let mut t_parser = toml::Parser::new(&mod_string);
        let tml = t_parser.parse();

        if tml.is_none() {
            for err in &t_parser.errors {
                let (loline, locol) = t_parser.to_linecol(err.lo);
                let (hiline, hicol) = t_parser.to_linecol(err.hi);
                println!("{}:{}:{}-{}:{} error: {}",
                         path, loline, locol, hiline, hicol, err.desc);
            }
            panic!("Unrecoverable error while parsing module config");

        }
        let module_opts = toml::Value::Table(tml.unwrap());

        Ok(toml::decode(module_opts).unwrap())
    }
}

#[derive(Debug, RustcDecodable)]
pub struct MetaOpts {
    pub name: String,
    pub version: String,
    pub author: String,
    pub license: String
}

#[derive(Debug, RustcDecodable)]
pub struct OptionsOpts {
    pub strip_whitespace: Option<bool>,
    pub core: Option<String>
}

pub struct Module<'a> {
    path: &'a Path, // Sub paths are determined relative to this one
    options: Option<ModuleOpts>
}

impl<'b> Module<'b> {
    pub fn new(path:&'b Path) -> Module {
        Module {
            path: path,
            options: None
        }
    }

    pub fn get_opts(&'b mut self) -> &'b ModuleOpts {
        match self.options {
            Some(ref opts) => opts,
            None => {
                self.options = Some(ModuleOpts::load(self.path.to_str().unwrap().to_string()).unwrap());
                self.get_opts()
            }
        }
    }
}
<commit_msg>) Made root module_opts public as well<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use toml;

#[derive(Debug, RustcDecodable)]
pub struct ModuleOpts {
    pub meta: MetaOpts,
    pub options: OptionsOpts
}

impl ModuleOpts {
    pub fn load(path: String) -> Result<ModuleOpts, &'static str> {
        let mut mod_string = String::new();
        let mut file = match File::open(&path) {
            Ok(file) => file,
            Err(_) => {
                return Err("Could not load config file")
            }
        };
        file.read_to_string(&mut mod_string)
        .unwrap_or_else(|e| panic!("Unrecoverable error while reading config: {}", e));

        let mut t_parser = toml::Parser::new(&mod_string);
        let tml = t_parser.parse();

        if tml.is_none() {
            for err in &t_parser.errors {
                let (loline, locol) = t_parser.to_linecol(err.lo);
                let (hiline, hicol) = t_parser.to_linecol(err.hi);
                println!("{}:{}:{}-{}:{} error: {}",
                         path, loline, locol, hiline, hicol, err.desc);
            }
            panic!("Unrecoverable error while parsing module config");

        }
        let module_opts = toml::Value::Table(tml.unwrap());

        Ok(toml::decode(module_opts).unwrap())
    }
}

#[derive(Debug, RustcDecodable)]
pub struct MetaOpts {
    pub name: String,
    pub version: String,
    pub author: String,
    pub license: String
}

#[derive(Debug, RustcDecodable)]
pub struct OptionsOpts {
    pub strip_whitespace: Option<bool>,
    pub core: Option<String>
}

pub struct Module<'a> {
    path: &'a Path, // Sub paths are determined relative to this one
    options: Option<ModuleOpts>
}

impl<'b> Module<'b> {
    pub fn new(path:&'b Path) -> Module {
        Module {
            path: path,
            options: None
        }
    }

    pub fn get_opts(&'b mut self) -> &'b ModuleOpts {
        match self.options {
            Some(ref opts) => opts,
            None => {
                self.options = Some(ModuleOpts::load(self.path.to_str().unwrap().to_string()).unwrap());
                self.get_opts()
            }
        }
    }
}
<|endoftext|>


<commit_before>use core::intrinsics;
use core::mem;

// Kernel-provided user-mode helper functions:
// https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt
unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool {
    let f: extern "C" fn (u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32);
    f(oldval, newval, ptr) == 0
}
unsafe fn __kuser_memory_barrier() {
    let f: extern "C" fn () = mem::transmute(0xffff0fa0u32);
    f();
}

// Word-align a pointer
fn align_ptr<T>(ptr: *mut T) -> *mut u32 {
    // This gives us a mask of 0 when T == u32 since the pointer is already
    // supposed to be aligned, which avoids any masking in that case.
    let ptr_mask = 3 & (4 - mem::size_of::<T>());
    (ptr as usize & !ptr_mask) as *mut u32
}

// Calculate the shift and mask of a value inside an aligned word
fn get_shift_mask<T>(ptr: *mut T) -> (u32, u32) {
    // Mask to get the low byte/halfword/word
    let mask = match mem::size_of::<T>() {
        1 => 0xff,
        2 => 0xffff,
        4 => 0xffffffff,
        _ => unreachable!(),
    };

    // If we are on big-endian then we need to adjust the shift accordingly
    let endian_adjust = if cfg!(target_endian = "little") {
        0
    } else {
        4 - mem::size_of::<T>() as u32
    };

    // Shift to get the desired element in the word
    let ptr_mask = 3 & (4 - mem::size_of::<T>());
    let shift = ((ptr as usize & ptr_mask) as u32 ^ endian_adjust) * 8;

    (shift, mask)
}

// Extract a value from an aligned word
fn extract_aligned(aligned: u32, shift: u32, mask: u32) -> u32 {
    (aligned >> shift) & mask
}

// Insert a value into an aligned word
fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 {
    (aligned & !(mask << shift)) | ((val & mask) << shift)
}

// Generic atomic read-modify-write operation
unsafe fn atomic_rmw<T, F: Fn(u32) -> u32>(ptr: *mut T, f: F) -> u32 {
    let aligned_ptr = align_ptr(ptr);
    let (shift, mask) = get_shift_mask(ptr);

    loop {
        let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr);
        let curval = extract_aligned(curval_aligned, shift, mask);
        let newval = f(curval);
        let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask);
        if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) {
            return curval;
        }
    }
}

// Generic atomic compare-exchange operation
unsafe fn atomic_cmpxchg<T>(ptr: *mut T, oldval: u32, newval: u32) -> u32 {
    let aligned_ptr = align_ptr(ptr);
    let (shift, mask) = get_shift_mask(ptr);

    loop {
        let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr);
        let curval = extract_aligned(curval_aligned, shift, mask);
        if curval != oldval {
            return curval;
        }
        let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask);
        if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) {
            return oldval;
        }
    }
}

macro_rules! atomic_rmw {
    ($name:ident, $ty:ty, $op:expr) => {
        #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
        pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty {
            atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty
        }
    }
}
macro_rules! atomic_cmpxchg {
    ($name:ident, $ty:ty) => {
        #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
        pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty {
            atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty
        }
    }
}

atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b));
atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a.wrapping_add(b));
atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a.wrapping_add(b));

atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b));
atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a.wrapping_sub(b));
atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a.wrapping_sub(b));

atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b);
atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b);
atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b);

atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b);
atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b);
atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b);

atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b);
atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b);
atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b);

atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !a & b);
atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !a & b);
atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !a & b);

atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b });

atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b });

atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b });

atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b });

atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b);
atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b);
atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b);

atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8);
atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16);
atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32);

#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe extern "C" fn __sync_synchronize() {
    __kuser_memory_barrier();
}
<commit_msg>Fix __sync_fetch_and_nand_* for pre-v6 ARM<commit_after>use core::intrinsics;
use core::mem;

// Kernel-provided user-mode helper functions:
// https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt
unsafe fn __kuser_cmpxchg(oldval: u32, newval: u32, ptr: *mut u32) -> bool {
    let f: extern "C" fn (u32, u32, *mut u32) -> u32 = mem::transmute(0xffff0fc0u32);
    f(oldval, newval, ptr) == 0
}
unsafe fn __kuser_memory_barrier() {
    let f: extern "C" fn () = mem::transmute(0xffff0fa0u32);
    f();
}

// Word-align a pointer
fn align_ptr<T>(ptr: *mut T) -> *mut u32 {
    // This gives us a mask of 0 when T == u32 since the pointer is already
    // supposed to be aligned, which avoids any masking in that case.
    let ptr_mask = 3 & (4 - mem::size_of::<T>());
    (ptr as usize & !ptr_mask) as *mut u32
}

// Calculate the shift and mask of a value inside an aligned word
fn get_shift_mask<T>(ptr: *mut T) -> (u32, u32) {
    // Mask to get the low byte/halfword/word
    let mask = match mem::size_of::<T>() {
        1 => 0xff,
        2 => 0xffff,
        4 => 0xffffffff,
        _ => unreachable!(),
    };

    // If we are on big-endian then we need to adjust the shift accordingly
    let endian_adjust = if cfg!(target_endian = "little") {
        0
    } else {
        4 - mem::size_of::<T>() as u32
    };

    // Shift to get the desired element in the word
    let ptr_mask = 3 & (4 - mem::size_of::<T>());
    let shift = ((ptr as usize & ptr_mask) as u32 ^ endian_adjust) * 8;

    (shift, mask)
}

// Extract a value from an aligned word
fn extract_aligned(aligned: u32, shift: u32, mask: u32) -> u32 {
    (aligned >> shift) & mask
}

// Insert a value into an aligned word
fn insert_aligned(aligned: u32, val: u32, shift: u32, mask: u32) -> u32 {
    (aligned & !(mask << shift)) | ((val & mask) << shift)
}

// Generic atomic read-modify-write operation
unsafe fn atomic_rmw<T, F: Fn(u32) -> u32>(ptr: *mut T, f: F) -> u32 {
    let aligned_ptr = align_ptr(ptr);
    let (shift, mask) = get_shift_mask(ptr);

    loop {
        let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr);
        let curval = extract_aligned(curval_aligned, shift, mask);
        let newval = f(curval);
        let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask);
        if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) {
            return curval;
        }
    }
}

// Generic atomic compare-exchange operation
unsafe fn atomic_cmpxchg<T>(ptr: *mut T, oldval: u32, newval: u32) -> u32 {
    let aligned_ptr = align_ptr(ptr);
    let (shift, mask) = get_shift_mask(ptr);

    loop {
        let curval_aligned = intrinsics::atomic_load_unordered(aligned_ptr);
        let curval = extract_aligned(curval_aligned, shift, mask);
        if curval != oldval {
            return curval;
        }
        let newval_aligned = insert_aligned(curval_aligned, newval, shift, mask);
        if __kuser_cmpxchg(curval_aligned, newval_aligned, aligned_ptr) {
            return oldval;
        }
    }
}

macro_rules! atomic_rmw {
    ($name:ident, $ty:ty, $op:expr) => {
        #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
        pub unsafe extern "C" fn $name(ptr: *mut $ty, val: $ty) -> $ty {
            atomic_rmw(ptr, |x| $op(x as $ty, val) as u32) as $ty
        }
    }
}
macro_rules! atomic_cmpxchg {
    ($name:ident, $ty:ty) => {
        #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
        pub unsafe extern "C" fn $name(ptr: *mut $ty, oldval: $ty, newval: $ty) -> $ty {
            atomic_cmpxchg(ptr, oldval as u32, newval as u32) as $ty
        }
    }
}

atomic_rmw!(__sync_fetch_and_add_1, u8, |a: u8, b: u8| a.wrapping_add(b));
atomic_rmw!(__sync_fetch_and_add_2, u16, |a: u16, b: u16| a.wrapping_add(b));
atomic_rmw!(__sync_fetch_and_add_4, u32, |a: u32, b: u32| a.wrapping_add(b));

atomic_rmw!(__sync_fetch_and_sub_1, u8, |a: u8, b: u8| a.wrapping_sub(b));
atomic_rmw!(__sync_fetch_and_sub_2, u16, |a: u16, b: u16| a.wrapping_sub(b));
atomic_rmw!(__sync_fetch_and_sub_4, u32, |a: u32, b: u32| a.wrapping_sub(b));

atomic_rmw!(__sync_fetch_and_and_1, u8, |a: u8, b: u8| a & b);
atomic_rmw!(__sync_fetch_and_and_2, u16, |a: u16, b: u16| a & b);
atomic_rmw!(__sync_fetch_and_and_4, u32, |a: u32, b: u32| a & b);

atomic_rmw!(__sync_fetch_and_or_1, u8, |a: u8, b: u8| a | b);
atomic_rmw!(__sync_fetch_and_or_2, u16, |a: u16, b: u16| a | b);
atomic_rmw!(__sync_fetch_and_or_4, u32, |a: u32, b: u32| a | b);

atomic_rmw!(__sync_fetch_and_xor_1, u8, |a: u8, b: u8| a ^ b);
atomic_rmw!(__sync_fetch_and_xor_2, u16, |a: u16, b: u16| a ^ b);
atomic_rmw!(__sync_fetch_and_xor_4, u32, |a: u32, b: u32| a ^ b);

atomic_rmw!(__sync_fetch_and_nand_1, u8, |a: u8, b: u8| !(a & b));
atomic_rmw!(__sync_fetch_and_nand_2, u16, |a: u16, b: u16| !(a & b));
atomic_rmw!(__sync_fetch_and_nand_4, u32, |a: u32, b: u32| !(a & b));

atomic_rmw!(__sync_fetch_and_max_1, i8, |a: i8, b: i8| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_max_2, i16, |a: i16, b: i16| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_max_4, i32, |a: i32, b: i32| if a > b { a } else { b });

atomic_rmw!(__sync_fetch_and_umax_1, u8, |a: u8, b: u8| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_umax_2, u16, |a: u16, b: u16| if a > b { a } else { b });
atomic_rmw!(__sync_fetch_and_umax_4, u32, |a: u32, b: u32| if a > b { a } else { b });

atomic_rmw!(__sync_fetch_and_min_1, i8, |a: i8, b: i8| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_min_2, i16, |a: i16, b: i16| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_min_4, i32, |a: i32, b: i32| if a < b { a } else { b });

atomic_rmw!(__sync_fetch_and_umin_1, u8, |a: u8, b: u8| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_umin_2, u16, |a: u16, b: u16| if a < b { a } else { b });
atomic_rmw!(__sync_fetch_and_umin_4, u32, |a: u32, b: u32| if a < b { a } else { b });

atomic_rmw!(__sync_lock_test_and_set_1, u8, |_: u8, b: u8| b);
atomic_rmw!(__sync_lock_test_and_set_2, u16, |_: u16, b: u16| b);
atomic_rmw!(__sync_lock_test_and_set_4, u32, |_: u32, b: u32| b);

atomic_cmpxchg!(__sync_val_compare_and_swap_1, u8);
atomic_cmpxchg!(__sync_val_compare_and_swap_2, u16);
atomic_cmpxchg!(__sync_val_compare_and_swap_4, u32);

#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe extern "C" fn __sync_synchronize() {
    __kuser_memory_barrier();
}
<|endoftext|>


<commit_before>use std::{fmt, mem};
use std::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull};
use std::ascii::AsciiExt;

use AsciiCast;
use ascii::Ascii;
use ascii_string::AsciiString;

/// A borrowed ascii string, like a slice into an `AsciiString`.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AsciiStr {
    slice: [Ascii],
}

impl AsciiStr {
    /// Coerces into an `AsciiStr` slice.
    pub fn new<S: AsRef<AsciiStr> + ?Sized>(s: &S) -> &AsciiStr {
        s.as_ref()
    }

    /// Converts `&self` to a `&str` slice.
    pub fn as_str(&self) -> &str {
        unsafe { mem::transmute(&self.slice) }
    }

    /// Converts `&self` into a byte slice.
    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(&self.slice) }
    }

    /// Returns the entire string as slice of `Ascii` characters.
    pub fn as_slice(&self) -> &[Ascii] {
        &self.slice
    }

    /// Returns the entire string as mutable slice of `Ascii` characters.
    pub fn as_mut_slice(&mut self) -> &mut [Ascii] {
        &mut self.slice
    }

    /// Returns a raw pointer to the `AsciiStr`'s buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
    /// reallocated, which would also make any pointers to it invalid.
    pub fn as_ptr(&self) -> *const Ascii {
        self.as_slice().as_ptr()
    }

    /// Returns an unsafe mutable pointer to the `AsciiStr`'s buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
    /// reallocated, which would also make any pointers to it invalid.
    pub fn as_mut_ptr(&mut self) -> *mut Ascii {
        self.as_mut_slice().as_mut_ptr()
    }

    /// Copies the content of this `AsciiStr` into an owned `AsciiString`.
    pub fn to_ascii_string(&self) -> AsciiString {
        AsciiString::from(self.slice.to_vec())
    }

    /// Converts anything that can represent a byte slice into an `AsciiStr`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let foo = AsciiStr::from_bytes("foo");
    /// let err = AsciiStr::from_bytes("Ŋ");
    /// assert_eq!(foo.unwrap().as_str(), "foo");
    /// assert_eq!(err, Err(()));
    /// ```
    pub fn from_bytes<'a, B: ?Sized>(bytes: &'a B) -> Result<&'a AsciiStr, ()>
        where B: AsRef<[u8]>
    {
        unsafe {
            if bytes.as_ref().is_ascii() {
                Ok( mem::transmute(bytes.as_ref()) )
            } else {
                Err(())
            }
        }
    }

    /// Converts a borrowed string to a borrows ascii string.
    pub fn from_str<'a>(s: &'a str) -> Result<&'a AsciiStr, ()> {
        AsciiStr::from_bytes(s.as_bytes())
    }

    /// Returns the number of bytes in this ascii string.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let s = AsciiStr::from_bytes("foo").unwrap();
    /// assert_eq!(s.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.slice.len()
    }

    /// Returns true if the ascii string contains no bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let mut empty = AsciiStr::from_bytes("").unwrap();
    /// let mut full = AsciiStr::from_bytes("foo").unwrap();
    /// assert!(empty.is_empty());
    /// assert!(!full.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns an ascii string slice with leading and trailing whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace", example.trim());
    /// ```
    pub fn trim(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim()) }
    }

    /// Returns a string slice with leading whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace  \t", example.trim_left());
    /// ```
    pub fn trim_left(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_left()) }
    }

    /// Returns a string slice with trainling whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("  \twhite \tspace", example.trim_right());
    /// ```
    pub fn trim_right(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_right()) }
    }
}

impl PartialEq<str> for AsciiStr {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl PartialEq<AsciiStr> for str {
    fn eq(&self, other: &AsciiStr) -> bool {
        other.as_str() == self
    }
}

/*
impl PartialOrd<AsciiString> for AsciiStr {
    #[inline]
    fn partial_cmp(&self, other: &AsciiString) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}
*/

impl ToOwned for AsciiStr {
    type Owned = AsciiString;

    fn to_owned(&self) -> AsciiString {
        self.to_ascii_string()
    }
}

impl AsRef<[u8]> for AsciiStr {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl AsRef<str> for AsciiStr {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl fmt::Display for AsciiStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl fmt::Debug for AsciiStr {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       fmt::Debug::fmt(self.as_str(), f)
   }
}

macro_rules! impl_index {
    ($lhs:ty, $idx:ty, $rhs:ty) => {
        impl Index<$idx> for $lhs {
            type Output = $rhs;

            #[inline]
            fn index(&self, index: $idx) -> &$rhs {
                unsafe { mem::transmute(&self.slice[index]) }
            }
        }

        impl IndexMut<$idx> for $lhs {
            #[inline]
            fn index_mut(&mut self, index: $idx) -> &mut $rhs {
                unsafe { mem::transmute(&mut self.slice[index]) }
            }
        }
    }
}

impl_index! { AsciiStr, usize, Ascii }
impl_index! { AsciiStr, Range<usize>, AsciiStr }
impl_index! { AsciiStr, RangeTo<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFrom<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFull, AsciiStr }

#[cfg(feature = "unstable")]
impl AsciiExt for AsciiStr {
    type Owned = AsciiString;

    #[inline]
    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn to_ascii_lowercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.len() == other.len() &&
        self.slice.iter().zip(other.slice.iter()).all(|(a, b)| a.eq_ignore_ascii_case(b))
    }

    fn make_ascii_uppercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_uppercase();
        }
    }

    fn make_ascii_lowercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_lowercase();
        }
    }
}

impl<'a> AsciiCast<'a> for [u8] {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

impl<'a> AsciiCast<'a> for str {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

#[cfg(test)]
mod tests {
    use AsciiCast;
    use super::AsciiStr;

    #[test]
    fn as_str() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_str(), "( ;");
        assert_eq!(AsRef::<str>::as_ref(v), "( ;");
    }

    #[test]
    fn as_bytes() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_bytes(), b"( ;");
        assert_eq!(AsRef::<[u8]>::as_ref(v), b"( ;");
    }

    #[test]
    fn fmt_display_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{}", s), "abc".to_string());
    }

    #[test]
    fn fmt_debug_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{:?}", s), "\"abc\"".to_string());
    }
}
<commit_msg>Add a lot of From and Into impls for AsciiStr<commit_after>use std::{fmt, mem};
use std::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull};
use std::ascii::AsciiExt;

use AsciiCast;
use ascii::Ascii;
use ascii_string::AsciiString;

/// A borrowed ascii string, like a slice into an `AsciiString`.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AsciiStr {
    slice: [Ascii],
}

impl AsciiStr {
    /// Coerces into an `AsciiStr` slice.
    pub fn new<S: AsRef<AsciiStr> + ?Sized>(s: &S) -> &AsciiStr {
        s.as_ref()
    }

    /// Converts `&self` to a `&str` slice.
    pub fn as_str(&self) -> &str {
        unsafe { mem::transmute(&self.slice) }
    }

    /// Converts `&self` into a byte slice.
    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(&self.slice) }
    }

    /// Returns the entire string as slice of `Ascii` characters.
    pub fn as_slice(&self) -> &[Ascii] {
        &self.slice
    }

    /// Returns the entire string as mutable slice of `Ascii` characters.
    pub fn as_mut_slice(&mut self) -> &mut [Ascii] {
        &mut self.slice
    }

    /// Returns a raw pointer to the `AsciiStr`'s buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
    /// reallocated, which would also make any pointers to it invalid.
    pub fn as_ptr(&self) -> *const Ascii {
        self.as_slice().as_ptr()
    }

    /// Returns an unsafe mutable pointer to the `AsciiStr`'s buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
    /// reallocated, which would also make any pointers to it invalid.
    pub fn as_mut_ptr(&mut self) -> *mut Ascii {
        self.as_mut_slice().as_mut_ptr()
    }

    /// Copies the content of this `AsciiStr` into an owned `AsciiString`.
    pub fn to_ascii_string(&self) -> AsciiString {
        AsciiString::from(self.slice.to_vec())
    }

    /// Converts anything that can represent a byte slice into an `AsciiStr`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let foo = AsciiStr::from_bytes("foo");
    /// let err = AsciiStr::from_bytes("Ŋ");
    /// assert_eq!(foo.unwrap().as_str(), "foo");
    /// assert_eq!(err, Err(()));
    /// ```
    pub fn from_bytes<'a, B: ?Sized>(bytes: &'a B) -> Result<&'a AsciiStr, ()>
        where B: AsRef<[u8]>
    {
        unsafe {
            if bytes.as_ref().is_ascii() {
                Ok( mem::transmute(bytes.as_ref()) )
            } else {
                Err(())
            }
        }
    }

    /// Converts a borrowed string to a borrows ascii string.
    pub fn from_str<'a>(s: &'a str) -> Result<&'a AsciiStr, ()> {
        AsciiStr::from_bytes(s.as_bytes())
    }

    /// Returns the number of bytes in this ascii string.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let s = AsciiStr::from_bytes("foo").unwrap();
    /// assert_eq!(s.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.slice.len()
    }

    /// Returns true if the ascii string contains no bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let mut empty = AsciiStr::from_bytes("").unwrap();
    /// let mut full = AsciiStr::from_bytes("foo").unwrap();
    /// assert!(empty.is_empty());
    /// assert!(!full.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns an ascii string slice with leading and trailing whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace", example.trim());
    /// ```
    pub fn trim(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim()) }
    }

    /// Returns a string slice with leading whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace  \t", example.trim_left());
    /// ```
    pub fn trim_left(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_left()) }
    }

    /// Returns a string slice with trainling whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("  \twhite \tspace", example.trim_right());
    /// ```
    pub fn trim_right(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_right()) }
    }
}

impl PartialEq<str> for AsciiStr {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl PartialEq<AsciiStr> for str {
    fn eq(&self, other: &AsciiStr) -> bool {
        other.as_str() == self
    }
}

/*
impl PartialOrd<AsciiString> for AsciiStr {
    #[inline]
    fn partial_cmp(&self, other: &AsciiString) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}
*/

impl ToOwned for AsciiStr {
    type Owned = AsciiString;

    fn to_owned(&self) -> AsciiString {
        self.to_ascii_string()
    }
}

impl AsRef<[u8]> for AsciiStr {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl AsRef<str> for AsciiStr {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<'a> From<&'a[Ascii]> for &'a AsciiStr {
    fn from(slice: &[Ascii]) -> &AsciiStr {
        unsafe{ mem::transmute(slice) }
    }
}
impl From<Box<[Ascii]>> for Box<AsciiStr> {
    fn from(owned: Box<[Ascii]>) -> Box<AsciiStr> {
        unsafe{ mem::transmute(owned) }
    }
}

macro_rules! impl_into {
    ($wider: ty) => {
        impl<'a> From<&'a AsciiStr> for &'a$wider {
            fn from(slice: &AsciiStr) -> &$wider {
                unsafe{ mem::transmute(slice) }
            }
        }
        impl From<Box<AsciiStr>> for Box<$wider> {
            fn from(owned: Box<AsciiStr>) -> Box<$wider> {
                unsafe{ mem::transmute(owned) }
            }
        }
    }
}
impl_into! {[Ascii]}
impl_into! {[u8]}
impl_into! {str}

impl fmt::Display for AsciiStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl fmt::Debug for AsciiStr {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       fmt::Debug::fmt(self.as_str(), f)
   }
}

macro_rules! impl_index {
    ($lhs:ty, $idx:ty, $rhs:ty) => {
        impl Index<$idx> for $lhs {
            type Output = $rhs;

            #[inline]
            fn index(&self, index: $idx) -> &$rhs {
                unsafe { mem::transmute(&self.slice[index]) }
            }
        }

        impl IndexMut<$idx> for $lhs {
            #[inline]
            fn index_mut(&mut self, index: $idx) -> &mut $rhs {
                unsafe { mem::transmute(&mut self.slice[index]) }
            }
        }
    }
}

impl_index! { AsciiStr, usize, Ascii }
impl_index! { AsciiStr, Range<usize>, AsciiStr }
impl_index! { AsciiStr, RangeTo<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFrom<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFull, AsciiStr }

#[cfg(feature = "unstable")]
impl AsciiExt for AsciiStr {
    type Owned = AsciiString;

    #[inline]
    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn to_ascii_lowercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.len() == other.len() &&
        self.slice.iter().zip(other.slice.iter()).all(|(a, b)| a.eq_ignore_ascii_case(b))
    }

    fn make_ascii_uppercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_uppercase();
        }
    }

    fn make_ascii_lowercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_lowercase();
        }
    }
}

impl<'a> AsciiCast<'a> for [u8] {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

impl<'a> AsciiCast<'a> for str {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

#[cfg(test)]
mod tests {
    use AsciiCast;
    use super::AsciiStr;

    #[test]
    fn as_str() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_str(), "( ;");
        assert_eq!(AsRef::<str>::as_ref(v), "( ;");
    }

    #[test]
    fn as_bytes() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_bytes(), b"( ;");
        assert_eq!(AsRef::<[u8]>::as_ref(v), b"( ;");
    }

    #[test]
    fn fmt_display_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{}", s), "abc".to_string());
    }

    #[test]
    fn fmt_debug_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{:?}", s), "\"abc\"".to_string());
    }
}
<|endoftext|>


<commit_before>// Snow -- A FLAC decoding library in Rust
// Copyright (C) 2015  Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate snow;

fn main() {
    use std::io::{File, BufferedReader};
    use snow::FlacStream;
    let input = File::open(&Path::new("testsamples/foo.flac")).unwrap();
    let mut reader = BufferedReader::new(input);
    let mut stream = FlacStream::new(&mut reader).unwrap();
    let mut blocks = stream.blocks::<u16>();
    let block = blocks.read_next().unwrap();
    let left = block.channel(0);
    let right = block.channel(1);
    println!("left: {}\nright: {}", left.slice_to(12), right.slice_to(12));
}
<commit_msg>do not hard-code debug test file<commit_after>// Snow -- A FLAC decoding library in Rust
// Copyright (C) 2015  Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate snow;

fn main() {
    use std::io::{File, BufferedReader};
    use std::os::args;
    use snow::FlacStream;
    let input = File::open(&Path::new(&args()[1])).unwrap();
    let mut reader = BufferedReader::new(input);
    let mut stream = FlacStream::new(&mut reader).unwrap();
    let mut blocks = stream.blocks::<u16>();
    let block = blocks.read_next().unwrap();
    let left = block.channel(0);
    let right = block.channel(1);
    println!("left: {}\nright: {}", left.slice_to(12), right.slice_to(12));
}
<|endoftext|>


<commit_before>extern crate json_typegen_shared;
extern crate clap;

use json_typegen_shared::{codegen, codegen_from_macro, Options, infer_source_type};
use clap::{Arg, App};
use std::io::{self, Read, Write};
use std::fs::OpenOptions;

fn main_with_result() -> Result<(), Box<std::error::Error>> {
    let matches = App::new("JSON code generation CLI")
        .version("0.1.0")
        .about("Generate Rust types from JSON samples")
        .arg(
            Arg::with_name("input")
                .help("The input to generate types from. A sample, file, URL, or macro.")
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name("name")
                .short("n")
                .long("name")
                .help("Name for the root generated type. Default: Root.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .help("What file to write the output to. Default: standard output.")
                .takes_value(true),
        )
        .get_matches();

    let source = matches.value_of("input").expect("input argument is required");

    let input = if source == "-" {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;
        buffer
    } else {
        source.to_string()
    };

    let code = if input.trim().starts_with("json_typegen") {
        codegen_from_macro(&input)
    } else {
        let name = matches.value_of("name").unwrap_or("Root");
        codegen(&name, &infer_source_type(&input), Options::default())
    };

    if let Some(filename) = matches.value_of("output") {
        let mut file = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(filename)?;

        file.write_all(code?.as_bytes())?;
    } else {
        print!("{}", code?);
    }

    Ok(())
}

fn main() {
    let result = main_with_result();

    if let Err(e) = result {
        eprintln!("{}", e);
        std::process::exit(1);
    }
}
<commit_msg>CLI: Mention how to read from stdin in -h output<commit_after>extern crate json_typegen_shared;
extern crate clap;

use json_typegen_shared::{codegen, codegen_from_macro, Options, infer_source_type};
use clap::{Arg, App};
use std::io::{self, Read, Write};
use std::fs::OpenOptions;

fn main_with_result() -> Result<(), Box<std::error::Error>> {
    let matches = App::new("json_typegen CLI")
        .version("0.1.0")
        .about("Generate Rust types from JSON samples")
        .arg(
            Arg::with_name("input")
                .help(concat!(
                    "The input to generate types from. A sample, file, URL, or macro. To read ",
                    "from standard input, a dash, '-', can be used as the input argument."))
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name("name")
                .short("n")
                .long("name")
                .help("Name for the root generated type. Default: Root.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .help("What file to write the output to. Default: standard output.")
                .takes_value(true),
        )
        .get_matches();

    let source = matches.value_of("input").expect("input argument is required");

    let input = if source == "-" {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;
        buffer
    } else {
        source.to_string()
    };

    let code = if input.trim().starts_with("json_typegen") {
        codegen_from_macro(&input)
    } else {
        let name = matches.value_of("name").unwrap_or("Root");
        codegen(&name, &infer_source_type(&input), Options::default())
    };

    if let Some(filename) = matches.value_of("output") {
        let mut file = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(filename)?;

        file.write_all(code?.as_bytes())?;
    } else {
        print!("{}", code?);
    }

    Ok(())
}

fn main() {
    let result = main_with_result();

    if let Err(e) = result {
        eprintln!("{}", e);
        std::process::exit(1);
    }
}
<|endoftext|>