<commit_before>#![cfg_attr(
    feature = "nightly",
    feature(external_doc),
    doc(include = "../README.md")
)]
#![cfg_attr(
    not(feature = "nightly"),
    doc = "Check out documentation in [README.md](https://github.com/GoogleChromeLabs/wasm-bindgen-rayon)."
)]

/**
 * Copyright 2021 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
use js_sys::Promise;
use spmc::{channel, Receiver, Sender};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;

#[cfg(feature = "no-bundler")]
use js_sys::JsString;

// Naming is a workaround for https://github.com/rustwasm/wasm-bindgen/issues/2429
// and https://github.com/rustwasm/wasm-bindgen/issues/1762.
#[allow(non_camel_case_types)]
#[wasm_bindgen]
#[doc(hidden)]
pub struct wbg_rayon_PoolBuilder {
    num_threads: usize,
    sender: Sender<rayon::ThreadBuilder>,
    receiver: Receiver<rayon::ThreadBuilder>,
}

#[cfg_attr(
    not(feature = "no-bundler"),
    wasm_bindgen(module = "/src/workerHelpers.js")
)]
#[cfg_attr(
    feature = "no-bundler",
    wasm_bindgen(module = "/src/workerHelpers.no-bundler.js")
)]
extern "C" {
    #[wasm_bindgen(js_name = startWorkers)]
    fn start_workers(module: JsValue, memory: JsValue, builder: wbg_rayon_PoolBuilder) -> Promise;
}

#[wasm_bindgen]
impl wbg_rayon_PoolBuilder {
    fn new(num_threads: usize) -> Self {
        let (sender, receiver) = channel();
        Self {
            num_threads,
            sender,
            receiver,
        }
    }

    #[cfg(feature = "no-bundler")]
    #[wasm_bindgen(js_name = mainJS)]
    pub fn main_js(&self) -> JsString {
        #[wasm_bindgen]
        extern "C" {
            #[wasm_bindgen(js_namespace = ["import", "meta"], js_name = url)]
            static URL: JsString;
        }

        URL.clone()
    }

    #[wasm_bindgen(js_name = numThreads)]
    pub fn num_threads(&self) -> usize {
        self.num_threads
    }

    pub fn receiver(&self) -> *const Receiver<rayon::ThreadBuilder> {
        &self.receiver
    }

    // This should be called by the JS side once all the Workers are spawned.
    // Important: it must take `self` by reference, otherwise
    // `start_worker_thread` will try to receive a message on a moved value.
    pub fn build(&mut self) {
        rayon::ThreadPoolBuilder::new()
            .num_threads(self.num_threads)
            // We could use postMessage here instead of Rust channels,
            // but currently we can't due to a Chrome bug that will cause
            // the main thread to lock up before it even sends the message:
            // https://bugs.chromium.org/p/chromium/issues/detail?id=1075645
            .spawn_handler(move |thread| {
                // Note: `send` will return an error if there are no receivers.
                // We can use it because all the threads are spawned and ready to accept
                // messages by the time we call `build()` to instantiate spawn handler.
                self.sender.send(thread).unwrap_throw();
                Ok(())
            })
            .build_global()
            .unwrap_throw();
    }
}

#[wasm_bindgen(js_name = initThreadPool)]
#[doc(hidden)]
pub fn init_thread_pool(num_threads: usize) -> Promise {
    start_workers(
        wasm_bindgen::module(),
        wasm_bindgen::memory(),
        wbg_rayon_PoolBuilder::new(num_threads),
    )
}

#[wasm_bindgen]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[doc(hidden)]
pub fn wbg_rayon_start_worker(receiver: *const Receiver<rayon::ThreadBuilder>)
where
    // Statically assert that it's safe to accept `Receiver` from another thread.
    Receiver<rayon::ThreadBuilder>: Sync,
{
    // This is safe, because we know it came from a reference to PoolBuilder,
    // allocated on the heap by wasm-bindgen and dropped only once all the
    // threads are running.
    //
    // The only way to violate safety is if someone externally calls
    // `exports.wbg_rayon_start_worker(garbageValue)`, but then no Rust tools
    // would prevent us from issues anyway.
    let receiver = unsafe { &*receiver };
    // Wait for a task (`ThreadBuilder`) on the channel, and, once received,
    // start executing it.
    //
    // On practice this will start running Rayon's internal event loop.
    receiver.recv().unwrap_throw().run()
}
<commit_msg>Check that user enabled `atomics` feature<commit_after>#![cfg_attr(
    feature = "nightly",
    feature(external_doc),
    doc(include = "../README.md")
)]
#![cfg_attr(
    not(feature = "nightly"),
    doc = "Check out documentation in [README.md](https://github.com/GoogleChromeLabs/wasm-bindgen-rayon)."
)]

// Note: `atomics` is whitelisted in `target_feature` detection, but `bulk-memory` isn't,
// so we can check only presence of the former. This should be enough to catch most common
// mistake (forgetting to pass `RUSTFLAGS` altogether).
#[cfg(not(target_feature = "atomics"))]
compile_error!("Did you forget to enable `atomics` and `bulk-memory` features as outlined in wasm-bindgen-rayon README?");

/**
 * Copyright 2021 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
use js_sys::Promise;
use spmc::{channel, Receiver, Sender};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;

#[cfg(feature = "no-bundler")]
use js_sys::JsString;

// Naming is a workaround for https://github.com/rustwasm/wasm-bindgen/issues/2429
// and https://github.com/rustwasm/wasm-bindgen/issues/1762.
#[allow(non_camel_case_types)]
#[wasm_bindgen]
#[doc(hidden)]
pub struct wbg_rayon_PoolBuilder {
    num_threads: usize,
    sender: Sender<rayon::ThreadBuilder>,
    receiver: Receiver<rayon::ThreadBuilder>,
}

#[cfg_attr(
    not(feature = "no-bundler"),
    wasm_bindgen(module = "/src/workerHelpers.js")
)]
#[cfg_attr(
    feature = "no-bundler",
    wasm_bindgen(module = "/src/workerHelpers.no-bundler.js")
)]
extern "C" {
    #[wasm_bindgen(js_name = startWorkers)]
    fn start_workers(module: JsValue, memory: JsValue, builder: wbg_rayon_PoolBuilder) -> Promise;
}

#[wasm_bindgen]
impl wbg_rayon_PoolBuilder {
    fn new(num_threads: usize) -> Self {
        let (sender, receiver) = channel();
        Self {
            num_threads,
            sender,
            receiver,
        }
    }

    #[cfg(feature = "no-bundler")]
    #[wasm_bindgen(js_name = mainJS)]
    pub fn main_js(&self) -> JsString {
        #[wasm_bindgen]
        extern "C" {
            #[wasm_bindgen(js_namespace = ["import", "meta"], js_name = url)]
            static URL: JsString;
        }

        URL.clone()
    }

    #[wasm_bindgen(js_name = numThreads)]
    pub fn num_threads(&self) -> usize {
        self.num_threads
    }

    pub fn receiver(&self) -> *const Receiver<rayon::ThreadBuilder> {
        &self.receiver
    }

    // This should be called by the JS side once all the Workers are spawned.
    // Important: it must take `self` by reference, otherwise
    // `start_worker_thread` will try to receive a message on a moved value.
    pub fn build(&mut self) {
        rayon::ThreadPoolBuilder::new()
            .num_threads(self.num_threads)
            // We could use postMessage here instead of Rust channels,
            // but currently we can't due to a Chrome bug that will cause
            // the main thread to lock up before it even sends the message:
            // https://bugs.chromium.org/p/chromium/issues/detail?id=1075645
            .spawn_handler(move |thread| {
                // Note: `send` will return an error if there are no receivers.
                // We can use it because all the threads are spawned and ready to accept
                // messages by the time we call `build()` to instantiate spawn handler.
                self.sender.send(thread).unwrap_throw();
                Ok(())
            })
            .build_global()
            .unwrap_throw();
    }
}

#[wasm_bindgen(js_name = initThreadPool)]
#[doc(hidden)]
pub fn init_thread_pool(num_threads: usize) -> Promise {
    start_workers(
        wasm_bindgen::module(),
        wasm_bindgen::memory(),
        wbg_rayon_PoolBuilder::new(num_threads),
    )
}

#[wasm_bindgen]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[doc(hidden)]
pub fn wbg_rayon_start_worker(receiver: *const Receiver<rayon::ThreadBuilder>)
where
    // Statically assert that it's safe to accept `Receiver` from another thread.
    Receiver<rayon::ThreadBuilder>: Sync,
{
    // This is safe, because we know it came from a reference to PoolBuilder,
    // allocated on the heap by wasm-bindgen and dropped only once all the
    // threads are running.
    //
    // The only way to violate safety is if someone externally calls
    // `exports.wbg_rayon_start_worker(garbageValue)`, but then no Rust tools
    // would prevent us from issues anyway.
    let receiver = unsafe { &*receiver };
    // Wait for a task (`ThreadBuilder`) on the channel, and, once received,
    // start executing it.
    //
    // On practice this will start running Rayon's internal event loop.
    receiver.recv().unwrap_throw().run()
}
<|endoftext|>


<commit_before>extern crate regex;

use regex::{Captures, Regex};
use std::collections::BTreeMap;

const GROK_PATTERN: &'static str = r"%\{(?P<name>(?P<pattern>[A-z0-9]+)(?::(?P<subname>[A-z0-9_:;/\s\.]+))?)(?:=(?P<definition>(?:(?:[^{}]+|\.+)+)+))?\}";

pub struct Matches<'a> {
    captures: Captures<'a>,
    alias: &'a BTreeMap<String, String>
}

impl<'a> Matches<'a> {
    pub fn new(captures: Captures<'a>, alias: &'a BTreeMap<String, String>) -> Self {
        Matches { captures: captures, alias: alias }
    }

    pub fn get(&self, name: &str) -> Option<&str> {
        match self.alias.get(name) {
            Some(real) => self.captures.name(real).map(|m| m.as_str()),
            None => None,
        }
    }
}

pub struct Pattern {
    regex: Regex,
    alias: BTreeMap<String, String>,
}

impl Pattern {
    pub fn new(regex: &str, alias: BTreeMap<String, String>) -> Self {
        Pattern {
            regex: Regex::new(regex).expect("Could not compile regex!"),
            alias: alias,
        }
    }

    pub fn match_against<'a>(&'a self, text: &'a str) -> Option<Matches<'a>> {
        match self.regex.captures(&text) {
            Some(captures) => Some(Matches::new(captures, &self.alias)),
            None => None,
        }
    }
}

pub struct Grok {
    definitions: BTreeMap<String, String>,
}

impl Grok {
    /// Creates a new `Grok` instance with no patterns.
    pub fn new() -> Self {
        Grok {
            definitions: BTreeMap::new(),
        }
    }

    /// Inserts a custom pattern.
    pub fn insert_definition<S: Into<String>>(&mut self, name: S, pattern: S) {
        self.definitions.insert(name.into(), pattern.into());
    }

    /// Compiles the given pattern, making it ready for matching.
    pub fn compile(&mut self, pattern: &str, named_only: bool) -> Pattern {
        let mut named_regex = String::from(pattern);
        let original_grok_pattern = pattern;
        let mut alias: BTreeMap<String, String> = BTreeMap::new();

        let mut index = 0;
        let mut iteration_left = 1000;
        let mut continue_iteration = true;

        let grok_regex = Regex::new(GROK_PATTERN).unwrap();
        while continue_iteration {
            continue_iteration = false;
            if iteration_left <= 0 {
                panic!(
                    "Deep recursion pattern compilation of {:?}",
                    original_grok_pattern
                );
            }
            iteration_left -= 1;

            let capture = named_regex.clone();
            if let Some(m) = grok_regex.captures(&capture) {
                continue_iteration = true;

                let mut name = String::from(m.name("name").unwrap().as_str());
                if let Some(definition) = m.name("definition") {
                    self.insert_definition(m.name("pattern").unwrap().as_str(), definition.as_str());
                    name = format!("{}={}", name, definition.as_str());
                }

                let n = format!("%{{{}}}", name);
                let count = named_regex.matches(&n).count();
                for _ in 0..count {
                    let definition_of_pattern = self.definitions.get(m.name("pattern").unwrap().as_str());
                    if definition_of_pattern.is_none() {
                        panic!("No definition for key '{}' found, aborting", m.name("pattern").unwrap().as_str());
                    }
                    let mut replacement = format!("(?P<name{}>{})", index, definition_of_pattern.unwrap());
                    if named_only && m.name("subname").is_none() {
                        replacement = format!("(?:{})", definition_of_pattern.unwrap());
                    }

                    let name_and_index = format!("name{}", index);
                    if m.name("subname").is_some() {
                        alias.insert(m.name("subname").unwrap().as_str().into(), name_and_index);
                    } else {
                        alias.insert(name.clone(), name_and_index);
                    }

                    let search_string = format!("%{{{}}}", name);
                    named_regex = named_regex.replacen(&search_string, &replacement, 1);
                    index += 1;
                }
            }
        }

        if named_regex.is_empty() {
            panic!("Pattern not found");
        }
        Pattern::new(&named_regex, alias)
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_simple_anonymous_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        let pattern = grok.compile("%{USERNAME}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("USERNAME").unwrap());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("USERNAME").unwrap());
    }

    #[test]
    fn test_simple_named_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        let pattern = grok.compile("%{USERNAME:usr}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("usr").unwrap());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("usr").unwrap());
    }

    #[test]
    fn test_alias_anonymous_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        grok.insert_definition("USER", r"%{USERNAME}");
        let pattern = grok.compile("%{USER}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("USER").unwrap());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("USER").unwrap());
    }

    #[test]
    fn test_ailas_named_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        grok.insert_definition("USER", r"%{USERNAME}");
        let pattern = grok.compile("%{USER:usr}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("usr").unwrap());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("usr").unwrap());
    }

    #[test]
    fn test_composite_or_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("MAC", r"(?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})");
        grok.insert_definition("CISCOMAC", r"(?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})");
        grok.insert_definition("WINDOWSMAC", r"(?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})");
        grok.insert_definition("COMMONMAC", r"(?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})");
        let pattern = grok.compile("%{MAC}", false);

        let matches = pattern.match_against("5E:FF:56:A2:AF:15").expect("No matches found!");
        assert_eq!("5E:FF:56:A2:AF:15", matches.get("MAC").unwrap());
        let matches = pattern.match_against("hello! 5E:FF:56:A2:AF:15 what?").expect("No matches found!");
        assert_eq!("5E:FF:56:A2:AF:15", matches.get("MAC").unwrap());
        assert_eq!(true, pattern.match_against("5E:FF").is_none());
    }

    #[test]
    fn test_multiple_patterns() {
        let mut grok = Grok::new();
        grok.insert_definition("YEAR", r"(\d\d){1,2}");
        grok.insert_definition("MONTH", r"\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b");
        grok.insert_definition("DAY", r"(?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)");
        let pattern = grok.compile("%{DAY} %{MONTH} %{YEAR}", false);

        let matches = pattern.match_against("Monday March 2012").expect("No matches found!");
        assert_eq!("Monday", matches.get("DAY").unwrap());
        assert_eq!("March", matches.get("MONTH").unwrap());
        assert_eq!("2012", matches.get("YEAR").unwrap());
        assert_eq!(None, matches.get("unknown"));
    }

    #[test]
    fn test_named_only_single() {

    }

    #[test]
    fn test_named_only_multi() {

    }
}
<commit_msg>add len() for matches<commit_after>//! The `grok` library allows you to quickly parse and match potentially unstructured data
//! into a structed result. It is especially helpful when parsing logfiles of all kinds. This
//! [Rust](http://rust-lang.org) version is mainly a port from the [java version](https://github.com/thekrakken/java-grok)
//! which in drew inspiration from the original [ruby version](https://github.com/logstash-plugins/logstash-filter-grok).

extern crate regex;

use regex::{Captures, Regex};
use std::collections::BTreeMap;

const GROK_PATTERN: &'static str = r"%\{(?P<name>(?P<pattern>[A-z0-9]+)(?::(?P<subname>[A-z0-9_:;/\s\.]+))?)(?:=(?P<definition>(?:(?:[^{}]+|\.+)+)+))?\}";

pub struct Matches<'a> {
    captures: Captures<'a>,
    alias: &'a BTreeMap<String, String>
}

impl<'a> Matches<'a> {
    /// Instantiates the matches for a pattern after the match.
    pub fn new(captures: Captures<'a>, alias: &'a BTreeMap<String, String>) -> Self {
        Matches { captures: captures, alias: alias }
    }

    /// Gets the value for the name (or) alias if found, `None` otherwise.
    pub fn get(&self, name: &str) -> Option<&str> {
        match self.alias.get(name) {
            Some(real) => self.captures.name(real).map(|m| m.as_str()),
            None => None,
        }
    }

    /// Returns the number of matches.
    pub fn len(&self) -> usize {
        self.captures.len() - 1
    }
}

pub struct Pattern {
    regex: Regex,
    alias: BTreeMap<String, String>,
}

impl Pattern {
    /// Creates a new pattern from a raw regex string and an alias map to identify the
    /// fields properly.
    pub fn new(regex: &str, alias: BTreeMap<String, String>) -> Self {
        Pattern {
            regex: Regex::new(regex).expect("Could not compile regex!"),
            alias: alias,
        }
    }

    /// Matches this compiled `Pattern` against the text and returns the matches.
    pub fn match_against<'a>(&'a self, text: &'a str) -> Option<Matches<'a>> {
        match self.regex.captures(&text) {
            Some(captures) => Some(Matches::new(captures, &self.alias)),
            None => None,
        }
    }
}

pub struct Grok {
    definitions: BTreeMap<String, String>,
}

impl Grok {
    /// Creates a new `Grok` instance with no patterns.
    pub fn new() -> Self {
        Grok {
            definitions: BTreeMap::new(),
        }
    }

    /// Inserts a custom pattern.
    pub fn insert_definition<S: Into<String>>(&mut self, name: S, pattern: S) {
        self.definitions.insert(name.into(), pattern.into());
    }

    /// Compiles the given pattern, making it ready for matching.
    pub fn compile(&mut self, pattern: &str, named_only: bool) -> Pattern {
        let mut named_regex = String::from(pattern);
        let original_grok_pattern = pattern;
        let mut alias: BTreeMap<String, String> = BTreeMap::new();

        let mut index = 0;
        let mut iteration_left = 1000;
        let mut continue_iteration = true;

        let grok_regex = Regex::new(GROK_PATTERN).unwrap();
        while continue_iteration {
            continue_iteration = false;
            if iteration_left <= 0 {
                panic!(
                    "Deep recursion pattern compilation of {:?}",
                    original_grok_pattern
                );
            }
            iteration_left -= 1;

            let capture = named_regex.clone();
            if let Some(m) = grok_regex.captures(&capture) {
                continue_iteration = true;

                let mut name = String::from(m.name("name").unwrap().as_str());
                if let Some(definition) = m.name("definition") {
                    self.insert_definition(m.name("pattern").unwrap().as_str(), definition.as_str());
                    name = format!("{}={}", name, definition.as_str());
                }

                let n = format!("%{{{}}}", name);
                let count = named_regex.matches(&n).count();
                for _ in 0..count {
                    let definition_of_pattern = self.definitions.get(m.name("pattern").unwrap().as_str());
                    if definition_of_pattern.is_none() {
                        panic!("No definition for key '{}' found, aborting", m.name("pattern").unwrap().as_str());
                    }
                    let mut replacement = format!("(?P<name{}>{})", index, definition_of_pattern.unwrap());
                    if named_only && m.name("subname").is_none() {
                        replacement = format!("(?:{})", definition_of_pattern.unwrap());
                    }

                    let name_and_index = format!("name{}", index);
                    if m.name("subname").is_some() {
                        alias.insert(m.name("subname").unwrap().as_str().into(), name_and_index);
                    } else {
                        alias.insert(name.clone(), name_and_index);
                    }

                    let search_string = format!("%{{{}}}", name);
                    named_regex = named_regex.replacen(&search_string, &replacement, 1);
                    index += 1;
                }
            }
        }

        if named_regex.is_empty() {
            panic!("Pattern not found");
        }
        Pattern::new(&named_regex, alias)
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_simple_anonymous_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        let pattern = grok.compile("%{USERNAME}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("USERNAME").unwrap());
        assert_eq!(1, matches.len());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("USERNAME").unwrap());
        assert_eq!(1, matches.len());
    }

    #[test]
    fn test_simple_named_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        let pattern = grok.compile("%{USERNAME:usr}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("usr").unwrap());
        assert_eq!(1, matches.len());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("usr").unwrap());
        assert_eq!(1, matches.len());
    }

    #[test]
    fn test_alias_anonymous_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        grok.insert_definition("USER", r"%{USERNAME}");
        let pattern = grok.compile("%{USER}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("USER").unwrap());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("USER").unwrap());
    }

    #[test]
    fn test_ailas_named_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("USERNAME", r"[a-zA-Z0-9._-]+");
        grok.insert_definition("USER", r"%{USERNAME}");
        let pattern = grok.compile("%{USER:usr}", false);

        let matches = pattern.match_against("root").expect("No matches found!");
        assert_eq!("root", matches.get("usr").unwrap());
        let matches = pattern.match_against("john doe").expect("No matches found!");
        assert_eq!("john", matches.get("usr").unwrap());
    }

    #[test]
    fn test_composite_or_pattern() {
        let mut grok = Grok::new();
        grok.insert_definition("MAC", r"(?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})");
        grok.insert_definition("CISCOMAC", r"(?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})");
        grok.insert_definition("WINDOWSMAC", r"(?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})");
        grok.insert_definition("COMMONMAC", r"(?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})");
        let pattern = grok.compile("%{MAC}", false);

        let matches = pattern.match_against("5E:FF:56:A2:AF:15").expect("No matches found!");
        assert_eq!("5E:FF:56:A2:AF:15", matches.get("MAC").unwrap());
        assert_eq!(4, matches.len());
        let matches = pattern.match_against("hello! 5E:FF:56:A2:AF:15 what?").expect("No matches found!");
        assert_eq!("5E:FF:56:A2:AF:15", matches.get("MAC").unwrap());
        assert_eq!(true, pattern.match_against("5E:FF").is_none());
    }

    #[test]
    fn test_multiple_patterns() {
        let mut grok = Grok::new();
        grok.insert_definition("YEAR", r"(\d\d){1,2}");
        grok.insert_definition("MONTH", r"\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b");
        grok.insert_definition("DAY", r"(?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)");
        let pattern = grok.compile("%{DAY} %{MONTH} %{YEAR}", false);

        let matches = pattern.match_against("Monday March 2012").expect("No matches found!");
        assert_eq!("Monday", matches.get("DAY").unwrap());
        assert_eq!("March", matches.get("MONTH").unwrap());
        assert_eq!("2012", matches.get("YEAR").unwrap());
        assert_eq!(None, matches.get("unknown"));
    }

    #[test]
    fn test_named_only() {
        let mut grok = Grok::new();
        grok.insert_definition("MAC", r"(?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})");
        grok.insert_definition("CISCOMAC", r"(?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})");
        grok.insert_definition("WINDOWSMAC", r"(?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})");
        grok.insert_definition("COMMONMAC", r"(?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})");
        let pattern = grok.compile("%{MAC:macaddr}", true);

        let matches = pattern.match_against("5E:FF:56:A2:AF:15").expect("No matches found!");
        assert_eq!("5E:FF:56:A2:AF:15", matches.get("macaddr").unwrap());
        assert_eq!(1, matches.len());
        let matches = pattern.match_against("hello! 5E:FF:56:A2:AF:15 what?").expect("No matches found!");
        assert_eq!("5E:FF:56:A2:AF:15", matches.get("macaddr").unwrap());
        assert_eq!(true, pattern.match_against("5E:FF").is_none());
    }
}
<|endoftext|>


<commit_before>//! This library provides [`anyhow::Error`][Error], a trait object based error
//! type for easy idiomatic error handling in Rust applications.
//!
//!

//!
//! # Details
//!
//! - Use `Result<T, anyhow::Error>`, or equivalently `anyhow::Result<T>`, as
//!   the return type of any fallible function.
//!
//!   Within the function, use `?` to easily propagate any error that implements
//!   the `std::error::Error` trait.
//!
//!   ```
//!   # pub trait Deserialize {}
//!   #
//!   # mod serde_json {
//!   #     use super::Deserialize;
//!   #     use std::io;
//!   #
//!   #     pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # struct ClusterMap;
//!   #
//!   # impl Deserialize for ClusterMap {}
//!   #
//!   use anyhow::Result;
//!
//!   fn get_cluster_info() -> Result<ClusterMap> {
//!       let config = std::fs::read_to_string("cluster.json")?;
//!       let map: ClusterMap = serde_json::from_str(&config)?;
//!       Ok(map)
//!   }
//!   #
//!   # fn main() {}
//!   ```
//!
//! - Attach context to help the person troubleshooting the error understand
//!   where things went wrong. A low-level error like "No such file or
//!   directory" can be annoying to debug without more context about what higher
//!   level step the application was in the middle of.
//!
//!   ```
//!   # struct It;
//!   #
//!   # impl It {
//!   #     fn detach(&self) -> Result<()> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   use anyhow::{Context, Result};
//!
//!   fn main() -> Result<()> {
//!       # return Ok(());
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # let it = It;
//!       # let path = "./path/to/instrs.jsox";
//!       #
//!       it.detach().context("failed to detach the important thing")?;
//!
//!       let content = std::fs::read(path)
//!           .with_context(|| format!("failed to read instrs from {}", path))?;
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # Ok(())
//!   }
//!   ```
//!
//!   ```console
//!   Error: failed to read instrs from ./path/to/instrs.jsox
//!
//!   caused by:
//!       0: No such file or directory (os error 2)
//!   ```
//!
//! - Downcasting is supported and can be by value, by shared reference, or by
//!   mutable reference as needed.
//!
//!   ```
//!   # use anyhow::anyhow;
//!   # use std::fmt::{self, Display};
//!   # use std::task::Poll;
//!   #
//!   # #[derive(Debug)]
//!   # enum DataStoreError {
//!   #     Censored(()),
//!   # }
//!   #
//!   # impl Display for DataStoreError {
//!   #     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # impl std::error::Error for DataStoreError {}
//!   #
//!   # const REDACTED_CONTENT: () = ();
//!   #
//!   # let error = anyhow!("...");
//!   # let root_cause = &error;
//!   #
//!   # let ret =
//!   // If the error was caused by redaction, then return a
//!   // tombstone instead of the content.
//!   match root_cause.downcast_ref::<DataStoreError>() {
//!       Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
//!       None => Err(error),
//!   }
//!   # ;
//!   ```
//!
//! - A backtrace is captured and printed with the error if the underlying error
//!   type does not already provide its own. In order to see backtraces, the
//!   `RUST_LIB_BACKTRACE=1` environment variable must be defined.
//!
//! - Anyhow works with any error type that has an impl of `std::error::Error`,
//!   including ones defined in your crate. We do not bundle a `derive(Error)`
//!   macro but you can write the impls yourself or use a standalone macro like
//!   [err-derive].
//!
//!   [err-derive]: https://crates.io/crates/err-derive
//!
//!   ```
//!   # const IGNORE: &str = stringify! {
//!   #[derive(Error, Debug)]
//!   pub enum FormatError {
//!       #[error(display = "invalid header (expected {:?}, got {:?})", expected, found)]
//!       InvalidHeader {
//!           expected: String,
//!           found: String,
//!       },
//!       #[error(display = "missing attribute: {}", _0)]
//!       MissingAttribute(String),
//!   }
//!   # };
//!   ```
//!
//! - One-off error messages can be constructed using the `anyhow!` macro, which
//!   supports string interpolation and produces an `anyhow::Error`.
//!
//!   ```
//!   # use anyhow::{anyhow, Result};
//!   #
//!   # fn demo() -> Result<()> {
//!   #     let missing = "...";
//!   return Err(anyhow!("missing attribute: {}", missing));
//!   #     Ok(())
//!   # }
//!   ```
//!
//!

//!
//! # Acknowledgements
//!
//! The implementation of the `anyhow::Error` type is forked from
//! `fehler::Exception` ([https://github.com/withoutboats/fehler][fehler]). This
//! library just exposes it under the more standard `Error` / `Result`
//! terminology rather than the `throw!` / `#[throws]` / `Exception` language of
//! exceptions.
//!
//! [fehler]: https://github.com/withoutboats/fehler

#![doc(html_root_url = "https://docs.rs/anyhow/1.0.0-alpha.1")]
#![cfg_attr(backtrace, feature(backtrace))]

mod context;
mod error;

#[cfg(not(feature = "std"))]
compile_error!("no_std support is not implemented yet");

pub use crate::context::Context;
pub use crate::error::{Chain, Error};

/// `Result<T, Error>`
///
/// # Example
///
/// ```
/// # pub trait Deserialize {}
/// #
/// # mod serde_json {
/// #     use super::Deserialize;
/// #     use std::io;
/// #
/// #     pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
/// #         unimplemented!()
/// #     }
/// # }
/// #
/// # #[derive(Debug)]
/// # struct ClusterMap;
/// #
/// # impl Deserialize for ClusterMap {}
/// #
/// use anyhow::Result;
///
/// fn main() -> Result<()> {
///     # return Ok(());
///     let config = std::fs::read_to_string("cluster.json")?;
///     let map: ClusterMap = serde_json::from_str(&config)?;
///     println!("cluster info: {:#?}", map);
///     Ok(())
/// }
/// ```
pub type Result<T> = std::result::Result<T, Error>;

/// Return early with an error.
///
/// This macro is equivalent to `return Err(From::from($err))`.
#[macro_export]
macro_rules! bail {
    ($err:expr $(,)?) => {
        return std::result::Result::Err(std::convert::From::from($err));
    };
    ($fmt:expr, $($arg:tt)*) => {
        return std::result::Result::Err($crate::anyhow!($fmt, $($arg)*));
    };
}

/// Construct an ad-hoc error from a string.
///
/// This evaluates to an `Error`. It can take either just a string, or a format
/// string with arguments. It also can take any custom type which implements
/// `Debug` and `Display`.
#[macro_export]
macro_rules! anyhow {
    ($msg:expr $(,)?) => {
        $crate::private::new_adhoc($msg)
    };
    ($fmt:expr, $($arg:tt)*) => {
        $crate::private::new_adhoc(format!($fmt, $($arg)*))
    };
}

// Not public API.
#[doc(hidden)]
pub mod private {
    use crate::Error;
    use std::fmt::{Debug, Display};

    #[cfg(backtrace)]
    use std::backtrace::Backtrace;

    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        #[cfg(backtrace)]
        let backtrace = Some(Backtrace::capture());

        #[cfg(not(backtrace))]
        let backtrace = None;

        Error::new_adhoc(message, backtrace)
    }
}
<commit_msg>Document bail macro with examples<commit_after>//! This library provides [`anyhow::Error`][Error], a trait object based error
//! type for easy idiomatic error handling in Rust applications.
//!
//!

//!
//! # Details
//!
//! - Use `Result<T, anyhow::Error>`, or equivalently `anyhow::Result<T>`, as
//!   the return type of any fallible function.
//!
//!   Within the function, use `?` to easily propagate any error that implements
//!   the `std::error::Error` trait.
//!
//!   ```
//!   # pub trait Deserialize {}
//!   #
//!   # mod serde_json {
//!   #     use super::Deserialize;
//!   #     use std::io;
//!   #
//!   #     pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # struct ClusterMap;
//!   #
//!   # impl Deserialize for ClusterMap {}
//!   #
//!   use anyhow::Result;
//!
//!   fn get_cluster_info() -> Result<ClusterMap> {
//!       let config = std::fs::read_to_string("cluster.json")?;
//!       let map: ClusterMap = serde_json::from_str(&config)?;
//!       Ok(map)
//!   }
//!   #
//!   # fn main() {}
//!   ```
//!
//! - Attach context to help the person troubleshooting the error understand
//!   where things went wrong. A low-level error like "No such file or
//!   directory" can be annoying to debug without more context about what higher
//!   level step the application was in the middle of.
//!
//!   ```
//!   # struct It;
//!   #
//!   # impl It {
//!   #     fn detach(&self) -> Result<()> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   use anyhow::{Context, Result};
//!
//!   fn main() -> Result<()> {
//!       # return Ok(());
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # let it = It;
//!       # let path = "./path/to/instrs.jsox";
//!       #
//!       it.detach().context("failed to detach the important thing")?;
//!
//!       let content = std::fs::read(path)
//!           .with_context(|| format!("failed to read instrs from {}", path))?;
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # Ok(())
//!   }
//!   ```
//!
//!   ```console
//!   Error: failed to read instrs from ./path/to/instrs.jsox
//!
//!   caused by:
//!       0: No such file or directory (os error 2)
//!   ```
//!
//! - Downcasting is supported and can be by value, by shared reference, or by
//!   mutable reference as needed.
//!
//!   ```
//!   # use anyhow::anyhow;
//!   # use std::fmt::{self, Display};
//!   # use std::task::Poll;
//!   #
//!   # #[derive(Debug)]
//!   # enum DataStoreError {
//!   #     Censored(()),
//!   # }
//!   #
//!   # impl Display for DataStoreError {
//!   #     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # impl std::error::Error for DataStoreError {}
//!   #
//!   # const REDACTED_CONTENT: () = ();
//!   #
//!   # let error = anyhow!("...");
//!   # let root_cause = &error;
//!   #
//!   # let ret =
//!   // If the error was caused by redaction, then return a
//!   // tombstone instead of the content.
//!   match root_cause.downcast_ref::<DataStoreError>() {
//!       Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
//!       None => Err(error),
//!   }
//!   # ;
//!   ```
//!
//! - A backtrace is captured and printed with the error if the underlying error
//!   type does not already provide its own. In order to see backtraces, the
//!   `RUST_LIB_BACKTRACE=1` environment variable must be defined.
//!
//! - Anyhow works with any error type that has an impl of `std::error::Error`,
//!   including ones defined in your crate. We do not bundle a `derive(Error)`
//!   macro but you can write the impls yourself or use a standalone macro like
//!   [err-derive].
//!
//!   [err-derive]: https://crates.io/crates/err-derive
//!
//!   ```
//!   # const IGNORE: &str = stringify! {
//!   #[derive(Error, Debug)]
//!   pub enum FormatError {
//!       #[error(display = "invalid header (expected {:?}, got {:?})", expected, found)]
//!       InvalidHeader {
//!           expected: String,
//!           found: String,
//!       },
//!       #[error(display = "missing attribute: {}", _0)]
//!       MissingAttribute(String),
//!   }
//!   # };
//!   ```
//!
//! - One-off error messages can be constructed using the `anyhow!` macro, which
//!   supports string interpolation and produces an `anyhow::Error`.
//!
//!   ```
//!   # use anyhow::{anyhow, Result};
//!   #
//!   # fn demo() -> Result<()> {
//!   #     let missing = "...";
//!   return Err(anyhow!("missing attribute: {}", missing));
//!   #     Ok(())
//!   # }
//!   ```
//!
//!

//!
//! # Acknowledgements
//!
//! The implementation of the `anyhow::Error` type is forked from
//! `fehler::Exception` ([https://github.com/withoutboats/fehler][fehler]). This
//! library just exposes it under the more standard `Error` / `Result`
//! terminology rather than the `throw!` / `#[throws]` / `Exception` language of
//! exceptions.
//!
//! [fehler]: https://github.com/withoutboats/fehler

#![doc(html_root_url = "https://docs.rs/anyhow/1.0.0-alpha.1")]
#![cfg_attr(backtrace, feature(backtrace))]

mod context;
mod error;

#[cfg(not(feature = "std"))]
compile_error!("no_std support is not implemented yet");

pub use crate::context::Context;
pub use crate::error::{Chain, Error};

/// `Result<T, Error>`
///
/// # Example
///
/// ```
/// # pub trait Deserialize {}
/// #
/// # mod serde_json {
/// #     use super::Deserialize;
/// #     use std::io;
/// #
/// #     pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
/// #         unimplemented!()
/// #     }
/// # }
/// #
/// # #[derive(Debug)]
/// # struct ClusterMap;
/// #
/// # impl Deserialize for ClusterMap {}
/// #
/// use anyhow::Result;
///
/// fn main() -> Result<()> {
///     # return Ok(());
///     let config = std::fs::read_to_string("cluster.json")?;
///     let map: ClusterMap = serde_json::from_str(&config)?;
///     println!("cluster info: {:#?}", map);
///     Ok(())
/// }
/// ```
pub type Result<T> = std::result::Result<T, Error>;

/// Return early with an error.
///
/// This macro is equivalent to `return Err(From::from($err))`.
///
/// # Example
///
/// ```
/// # use anyhow::{bail, Result};
/// #
/// # fn has_permission(user: usize, resource: usize) -> bool {
/// #     true
/// # }
/// #
/// # fn main() -> Result<()> {
/// #     let user = 0;
/// #     let resource = 0;
/// #
/// if !has_permission(user, resource) {
///     bail!("permission denied for accessing {}", resource);
/// }
/// #     Ok(())
/// # }
/// ```
///
/// ```
/// # use anyhow::{bail, Result};
/// # use std::fmt::{self, Display};
/// #
/// # #[derive(Debug)]
/// # enum ScienceError {
/// #     RecursionLimitExceeded,
/// # }
/// #
/// # impl std::error::Error for ScienceError {}
/// #
/// # impl Display for ScienceError {
/// #     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
/// #         unimplemented!()
/// #     }
/// # }
/// #
/// # const MAX_DEPTH: usize = 1;
/// #
/// # const IGNORE: &str = stringify! {
/// #[derive(Error, Debug)]
/// enum ScienceError {
///     #[error(display = "recursion limit exceeded")]
///     RecursionLimitExceeded,
///     ...
/// }
/// # };
///
/// # fn main() -> Result<()> {
/// #     let depth = 0;
/// #
/// if depth > MAX_DEPTH {
///     bail!(ScienceError::RecursionLimitExceeded);
/// }
/// #     Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! bail {
    ($err:expr $(,)?) => {
        return std::result::Result::Err(std::convert::From::from($err));
    };
    ($fmt:expr, $($arg:tt)*) => {
        return std::result::Result::Err($crate::anyhow!($fmt, $($arg)*));
    };
}

/// Construct an ad-hoc error from a string.
///
/// This evaluates to an `Error`. It can take either just a string, or a format
/// string with arguments. It also can take any custom type which implements
/// `Debug` and `Display`.
#[macro_export]
macro_rules! anyhow {
    ($msg:expr $(,)?) => {
        $crate::private::new_adhoc($msg)
    };
    ($fmt:expr, $($arg:tt)*) => {
        $crate::private::new_adhoc(format!($fmt, $($arg)*))
    };
}

// Not public API.
#[doc(hidden)]
pub mod private {
    use crate::Error;
    use std::fmt::{Debug, Display};

    #[cfg(backtrace)]
    use std::backtrace::Backtrace;

    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        #[cfg(backtrace)]
        let backtrace = Some(Backtrace::capture());

        #[cfg(not(backtrace))]
        let backtrace = None;

        Error::new_adhoc(message, backtrace)
    }
}
<|endoftext|>


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

//! A library for interacting with Twitter.
//!
//! [Repository](https://github.com/QuietMisdreavus/twitter-rs)
//!
//! egg-mode is a Twitter library that aims to make as few assumptions about the user's codebase as
//! possible. Endpoints are exposed as bare functions where authentication details are passed in as
//! arguments, rather than as builder functions of a root "service" manager. The only exceptions to
//! this guideline are endpoints with many optional parameters, like posting a status update or
//! updating the metadata of a list.
//!
//! To use the Twitter API, there are some extra steps you need to do, both inside and outside of
//! your app code. Find the Authentication Overview and quick start guide in the [Token][]
//! documentation. The following examples already have a `token` on hand. In addition, using
//! asynchronous network calls, the various methods of this library assume the presence of a
//! [tokio][] `Core` whose `Handle` you pass to any given call. These are also assumed to be
//! present in each example.
//!
//! [Token]: enum.Token.html
//! [tokio]: https://tokio.rs
//!
//! To load the profile information of a single user:
//!
//! ```rust,no_run
//! # extern crate egg_mode; extern crate tokio_core;
//! # use egg_mode::Token; use tokio_core::reactor::{Core, Handle};
//! # fn main() {
//! # let (token, mut core, handle): (Token, Core, Handle) = unimplemented!();
//! let rustlang = core.run(egg_mode::user::show("rustlang", &token, &handle)).unwrap();
//!
//! println!("{} (@{})", rustlang.name, rustlang.screen_name);
//! # }
//! ```
//!
//! To post a new tweet:
//!
//! ```rust,no_run
//! # extern crate egg_mode; extern crate tokio_core;
//! # use egg_mode::Token; use tokio_core::reactor::{Core, Handle};
//! use egg_mode::tweet::DraftTweet;
//! # fn main() {
//! # let (token, mut core, handle): (Token, Core, Handle) = unimplemented!();
//!
//! let post = core.run(DraftTweet::new("Hey Twitter!").send(&token, &handle)).unwrap();
//! # }
//! ```
//!
//! # Types and Functions
//!
//! All of the main content of egg-mode is in submodules, but there are a few things here in the
//! crate root. To wit, it contains items related to authentication and a couple items that all the
//! submodules use.
//!
//! ## `Response<T>`
//!
//! Every method that calls Twitter and carries rate-limit information wraps its return value in a
//! [`Response`][] struct, that transmits this information to your app. From there, you can handle
//! the rate-limit information to hold off on that kind of request, or simply grab its `response`
//! field to get the output of whatever method you called. `Response` also implements `Deref`, so
//! for the most part you can access fields of the final result without having to grab the
//! `response` field directly.
//!
//! `Response` also has IntoIterator implementations and iterator creation methods that echo those
//! on `Vec<T>`, for methods that return Vecs. These methods and iterator types distribute the
//! rate-limit information across each iteration.
//!
//! [`Response`]: struct.Response.html
//!
//! ## `TwitterFuture<'a, T>`
//!
//! Any method that requires a network call will return a handle to the pending network call, in
//! most cases the type [`TwitterFuture`][]. This type (and any other `*Future` in this library)
//! implements the `Future` trait, for use as an asynchronous network call. All `Future`
//! implementations in this library use the `Error` enum as their Error value. For more information
//! on how to use the `Future` trait, check out the [Tokio documentation guides][].
//!
//! In addition, there is also a `FutureResponse` type alias, that corresponds to
//! `TwitterFuture<'a, Response<T>>`, for methods that return rate-limit information.
//!
//! [`TwitterFuture`]: struct.TwitterFuture.html
//! [Tokio documentation guides]: https://tokio.rs/docs/getting-started/tokio/
//!
//! ## Authentication Types/Functions
//!
//! The remaining types and methods are explained as part of the [authentication overview][Token],
//! with the exception of `verify_tokens`, which is a simple method to ensure a given token is
//! still valid.
//!
//! # Modules
//!
//! As there are many actions available in the Twitter API, egg-mode divides them roughly into
//! several modules by their shared purpose. Here's a sort of high-level overview, in rough order
//! from "most important" to "less directly used":
//!
//! ## Primary actions
//!
//! These could be considered the "core" actions within the Twitter API that egg-mode has made
//! available.
//!
//! * `tweet`: This module lets you act on tweets. Here you can find actions to load a user's
//!   timeline, post a new tweet, or like and retweet individual posts.
//! * `user`: This module lets you act on users, be it by following or unfollowing them, loading
//!   their profile information, blocking or muting them, or showing the relationship between two
//!   users.
//! * `search`: Due to the complexity of searching for tweets, it gets its own module.
//! * `direct`: Here you can work with a user's Direct Messages, either by loading DMs they've sent
//!   or received, or by sending new ones.
//! * `list`: This module lets you act on lists, from creating and deleting them, adding and
//!   removing users, or loading the posts made by their members.
//! * `media`: This module lets you upload images, GIFs, and videos to Twitter so you can attach
//!   them to tweets.
//!
//! ## Secondary actions
//!
//! These modules still contain direct actions for Twitter, but they can be considered as having
//! more of a helper role than something you might use directly.
//!
//! * `place`: Here are actions that look up physical locations that can be attached to tweets, as
//!   well at the `Place` struct that appears on tweets with locations attached.
//! * `service`: These are some miscellaneous methods that show information about the Twitter
//!   service as a whole, like loading the maximum length of t.co URLs or loading the current Terms
//!   of Service or Privacy Policy.
//!
//! ## Helper structs
//!
//! These modules contain some implementations that wrap some pattern seen in multiple "action"
//! modules.
//!
//! * `cursor`: This contains a helper trait and some helper structs that allow effective cursoring
//!   through certain collections of results from Twitter.
//! * `entities`: Whenever some text can be returned that may contain links, hashtags, media, or
//!   user mentions, its metadata is parsed into something that lives in this module.
//! * `error`: Any interaction with Twitter may result in an error condition, be it from finding a
//!   tweet or user that doesn't exist or the network connection being unavailable. All the error
//!   types are aggregated into an enum in this module.

#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_qualifications)]

#[macro_use] extern crate hyper;
#[macro_use] extern crate lazy_static;
extern crate futures;
extern crate tokio_core;
extern crate hyper_tls;
extern crate native_tls;
extern crate url;
extern crate rand;
extern crate hmac;
extern crate sha_1;
extern crate rustc_serialize;
extern crate mime;
extern crate chrono;
extern crate regex;

#[macro_use] mod common;
mod auth;
pub mod error;
pub mod user;
pub mod entities;
pub mod cursor;
pub mod tweet;
pub mod media;
pub mod search;
pub mod place;
pub mod direct;
pub mod service;
pub mod list;
mod links;

pub use auth::{KeyPair, Token, AuthFuture, request_token, authorize_url, authenticate_url,
               access_token, verify_tokens, bearer_token, invalidate_bearer};
pub use common::{Response, ResponseIter, ResponseIterRef,
                 ResponseIterMut, FutureResponse, TwitterFuture};
<commit_msg>rewrite the examples preamble<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/.

//! A library for interacting with Twitter.
//!
//! [Repository](https://github.com/QuietMisdreavus/twitter-rs)
//!
//! egg-mode is a Twitter library that aims to make as few assumptions about the user's codebase as
//! possible. Endpoints are exposed as bare functions where authentication details are passed in as
//! arguments, rather than as builder functions of a root "service" manager. The only exceptions to
//! this guideline are endpoints with many optional parameters, like posting a status update or
//! updating the metadata of a list.
//!
//! # About the examples in this documentation
//!
//! There are a couple prerequisites to using egg-mode, which its examples also assume:
//!
//! * All the network calls are tracked using a [tokio] `Core`, which is not supplied by this
//!   library. Specifically, each call needs a `Handle`, so that it can associate its network calls
//!   with that `Core`. These are introduced to each example "offscreen", to keep them from
//!   distracting from the example at hand.
//! * This library provides several types which implement the `Future` trait, but does not describe
//!   how to interact with them. The examples use the `Core::run` method to show a synchronous
//!   interaction, but more advanced scenarios are beyond the scope of this documentation. See the
//!   [tokio] documentation for more information.
//! * Twitter tracks API use through "tokens" which are managed by Twitter and processed separately
//!   for each "authenticated user" you wish to connect to your app. egg-mode's [Token]
//!   documentation describes how you can obtain one of these, but each example outside of the
//!   authentication documentation brings in a `Token` "offscreen", alongside the `Core` and
//!   `Handle`, to avoid distracting from the rest of the example.
//!
//! [Token]: enum.Token.html
//! [tokio]: https://tokio.rs
//!
//! To load the profile information of a single user:
//!
//! ```rust,no_run
//! # extern crate egg_mode; extern crate tokio_core;
//! # use egg_mode::Token; use tokio_core::reactor::{Core, Handle};
//! # fn main() {
//! # let (token, mut core, handle): (Token, Core, Handle) = unimplemented!();
//! let rustlang = core.run(egg_mode::user::show("rustlang", &token, &handle)).unwrap();
//!
//! println!("{} (@{})", rustlang.name, rustlang.screen_name);
//! # }
//! ```
//!
//! To post a new tweet:
//!
//! ```rust,no_run
//! # extern crate egg_mode; extern crate tokio_core;
//! # use egg_mode::Token; use tokio_core::reactor::{Core, Handle};
//! use egg_mode::tweet::DraftTweet;
//! # fn main() {
//! # let (token, mut core, handle): (Token, Core, Handle) = unimplemented!();
//!
//! let post = core.run(DraftTweet::new("Hey Twitter!").send(&token, &handle)).unwrap();
//! # }
//! ```
//!
//! # Types and Functions
//!
//! All of the main content of egg-mode is in submodules, but there are a few things here in the
//! crate root. To wit, it contains items related to authentication and a couple items that all the
//! submodules use.
//!
//! ## `Response<T>`
//!
//! Every method that calls Twitter and carries rate-limit information wraps its return value in a
//! [`Response`][] struct, that transmits this information to your app. From there, you can handle
//! the rate-limit information to hold off on that kind of request, or simply grab its `response`
//! field to get the output of whatever method you called. `Response` also implements `Deref`, so
//! for the most part you can access fields of the final result without having to grab the
//! `response` field directly.
//!
//! `Response` also has IntoIterator implementations and iterator creation methods that echo those
//! on `Vec<T>`, for methods that return Vecs. These methods and iterator types distribute the
//! rate-limit information across each iteration.
//!
//! [`Response`]: struct.Response.html
//!
//! ## `TwitterFuture<'a, T>`
//!
//! Any method that requires a network call will return a handle to the pending network call, in
//! most cases the type [`TwitterFuture`][]. This type (and any other `*Future` in this library)
//! implements the `Future` trait, for use as an asynchronous network call. All `Future`
//! implementations in this library use the `Error` enum as their Error value. For more information
//! on how to use the `Future` trait, check out the [Tokio documentation guides][].
//!
//! In addition, there is also a `FutureResponse` type alias, that corresponds to
//! `TwitterFuture<'a, Response<T>>`, for methods that return rate-limit information.
//!
//! [`TwitterFuture`]: struct.TwitterFuture.html
//! [Tokio documentation guides]: https://tokio.rs/docs/getting-started/tokio/
//!
//! ## Authentication Types/Functions
//!
//! The remaining types and methods are explained as part of the [authentication overview][Token],
//! with the exception of `verify_tokens`, which is a simple method to ensure a given token is
//! still valid.
//!
//! # Modules
//!
//! As there are many actions available in the Twitter API, egg-mode divides them roughly into
//! several modules by their shared purpose. Here's a sort of high-level overview, in rough order
//! from "most important" to "less directly used":
//!
//! ## Primary actions
//!
//! These could be considered the "core" actions within the Twitter API that egg-mode has made
//! available.
//!
//! * `tweet`: This module lets you act on tweets. Here you can find actions to load a user's
//!   timeline, post a new tweet, or like and retweet individual posts.
//! * `user`: This module lets you act on users, be it by following or unfollowing them, loading
//!   their profile information, blocking or muting them, or showing the relationship between two
//!   users.
//! * `search`: Due to the complexity of searching for tweets, it gets its own module.
//! * `direct`: Here you can work with a user's Direct Messages, either by loading DMs they've sent
//!   or received, or by sending new ones.
//! * `list`: This module lets you act on lists, from creating and deleting them, adding and
//!   removing users, or loading the posts made by their members.
//! * `media`: This module lets you upload images, GIFs, and videos to Twitter so you can attach
//!   them to tweets.
//!
//! ## Secondary actions
//!
//! These modules still contain direct actions for Twitter, but they can be considered as having
//! more of a helper role than something you might use directly.
//!
//! * `place`: Here are actions that look up physical locations that can be attached to tweets, as
//!   well at the `Place` struct that appears on tweets with locations attached.
//! * `service`: These are some miscellaneous methods that show information about the Twitter
//!   service as a whole, like loading the maximum length of t.co URLs or loading the current Terms
//!   of Service or Privacy Policy.
//!
//! ## Helper structs
//!
//! These modules contain some implementations that wrap some pattern seen in multiple "action"
//! modules.
//!
//! * `cursor`: This contains a helper trait and some helper structs that allow effective cursoring
//!   through certain collections of results from Twitter.
//! * `entities`: Whenever some text can be returned that may contain links, hashtags, media, or
//!   user mentions, its metadata is parsed into something that lives in this module.
//! * `error`: Any interaction with Twitter may result in an error condition, be it from finding a
//!   tweet or user that doesn't exist or the network connection being unavailable. All the error
//!   types are aggregated into an enum in this module.

#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_qualifications)]

#[macro_use] extern crate hyper;
#[macro_use] extern crate lazy_static;
extern crate futures;
extern crate tokio_core;
extern crate hyper_tls;
extern crate native_tls;
extern crate url;
extern crate rand;
extern crate hmac;
extern crate sha_1;
extern crate rustc_serialize;
extern crate mime;
extern crate chrono;
extern crate regex;

#[macro_use] mod common;
mod auth;
pub mod error;
pub mod user;
pub mod entities;
pub mod cursor;
pub mod tweet;
pub mod media;
pub mod search;
pub mod place;
pub mod direct;
pub mod service;
pub mod list;
mod links;

pub use auth::{KeyPair, Token, AuthFuture, request_token, authorize_url, authenticate_url,
               access_token, verify_tokens, bearer_token, invalidate_bearer};
pub use common::{Response, ResponseIter, ResponseIterRef,
                 ResponseIterMut, FutureResponse, TwitterFuture};
<|endoftext|>


<commit_before>use std::cmp;

extern crate kana;
use kana::Kana;

pub mod dict;
use dict::{Dict, KanaConversionTable};

pub fn to_hiragana(d: &Dict, s: &String) -> String {
    let s = s.to_lowercase();
    gen_convert(d, &s)
}

pub fn to_katakana(d: &Dict, s: &String) -> String {
    let s = s.to_uppercase();
    gen_convert(d, &s)
}

pub fn to_kana(d: &Dict, s: &String) -> String {
    gen_convert(d, &s)
}

// Converts a String as is
fn gen_convert(d: &Dict, s: &String) -> String {
    let mut ret: String = String::new();

    for w in normalize(s).split_whitespace() {
        let w: String = choose_kana(&w.to_string());
        let ss: Vec<String> = syllables(&d, &w)
            .iter()
            .map(|ref s| convert_syllable(d, &s))
            .collect();
        for syl in ss {
            ret.push_str(syl.as_str());
        }
    }
    ret
}

fn syllables(d: &Dict, original: &String) -> Vec<String> {
    if original.len() == 0 {
        return vec![];
    }

    let mut ret: Vec<String> = vec![];
    let maxlen = cmp::min(original.chars().count(), d.max_len()) + 1;

    for l in (1..maxlen).rev() {
        let tmp: String = original.chars().take(l).collect();

        if is_syllable(d, &tmp) {
            ret.push(tmp);
            let skipped: String = original.chars().skip(l).collect();
            let mut rest = syllables(d, &skipped);

            ret.append(&mut rest);

            return ret;
        }
    }

    // if a match wasn't found, add the first char to ret
    // let mut taken: Vec<String> = vec![original.chars().take(1).collect()];
    // ret.append(&mut taken);

    let taken: String = original.chars().take(1).collect();
    ret.push(taken);

    let skipped: String = original.chars().skip(1).collect();
    let mut rest = syllables(d, &skipped);
    ret.append(&mut rest);

    ret
}

// Given a String (expected to be normalized), returns `true` if it is a syllable and
// `false` otherwise.
fn is_syllable(d: &Dict, k: &String) -> bool {
    d.contains_key(k)
}

// Searches for uppercase characters in a String and, if it finds any, turns the whole String to
// uppercase.
fn choose_kana(s: &String) -> String {
    match s.chars().fold(false, |acc, c| acc || c.is_uppercase()) {
        true => s.to_uppercase(),
        false => s.to_string(),
    }
}

fn normalize(s: &String) -> String {
    let k = Kana::init();
    let mut ret: String = kana::nowidespace(s.as_str());

    ret = kana::nowideyen(ret.as_str());
    ret = kana::wide2ascii(ret.as_str());

    ret = k.combine(ret.as_str());
    ret = k.half2kana(ret.as_str());

    ret
}

// Converts a String (expected to be a syllable) to kana.
fn convert_syllable(d: &Dict, ow: &String) -> String {
    // <pingveno> Because String impls Borrow<str>
    // `&ow.to_string()` => `ow`
    match d.get(ow) {
        Some(c) => c.clone(),
        None => ow.clone(),
    }
}
<commit_msg>Generalize & simplify usage<commit_after>use std::cmp;

extern crate kana;
use kana::Kana;

pub mod dict;
use dict::{Dict, KanaConversionTable};

pub enum ConvType {
    Auto(String),
    Hira(String),
    Kata(String),
}

pub fn to_kana(d: &Dict, s: ConvType) -> String {
    let s = match s {
        ConvType::Auto(s) => s,
        ConvType::Hira(s) => s.to_lowercase(),
        ConvType::Kata(s) => s.to_uppercase(),
    };
    convert(d, &s)
}

// Converts a String as is
fn convert(d: &Dict, s: &String) -> String {
    let mut ret: String = String::new();

    for w in normalize(s).split_whitespace() {
        let w: String = choose_kana(&w.to_string());
        let ss: Vec<String> = syllables(&d, &w)
            .iter()
            .map(|ref s| convert_syllable(d, &s))
            .collect();
        for syl in ss {
            ret.push_str(syl.as_str());
        }
    }
    ret
}

fn syllables(d: &Dict, original: &String) -> Vec<String> {
    if original.len() == 0 {
        return vec![];
    }

    let mut ret: Vec<String> = vec![];
    let maxlen = cmp::min(original.chars().count(), d.max_len()) + 1;

    for l in (1..maxlen).rev() {
        let tmp: String = original.chars().take(l).collect();

        if is_syllable(d, &tmp) {
            ret.push(tmp);
            let skipped: String = original.chars().skip(l).collect();
            let mut rest = syllables(d, &skipped);

            ret.append(&mut rest);

            return ret;
        }
    }

    // if a match wasn't found, add the first char to ret
    // let mut taken: Vec<String> = vec![original.chars().take(1).collect()];
    // ret.append(&mut taken);

    let taken: String = original.chars().take(1).collect();
    ret.push(taken);

    let skipped: String = original.chars().skip(1).collect();
    let mut rest = syllables(d, &skipped);
    ret.append(&mut rest);

    ret
}

// Given a String (expected to be normalized), returns `true` if it is a syllable and
// `false` otherwise.
fn is_syllable(d: &Dict, k: &String) -> bool {
    d.contains_key(k)
}

// Searches for uppercase characters in a String and, if it finds any, turns the whole String to
// uppercase.
fn choose_kana(s: &String) -> String {
    match s.chars().fold(false, |acc, c| acc || c.is_uppercase()) {
        true => s.to_uppercase(),
        false => s.to_string(),
    }
}

fn normalize(s: &String) -> String {
    let k = Kana::init();
    let mut ret: String = s.clone();

    ret = kana::nowidespace(ret.as_str());
    ret = kana::nowideyen(ret.as_str());
    ret = kana::wide2ascii(ret.as_str());

    ret = k.combine(ret.as_str());
    ret = k.half2kana(ret.as_str());

    ret
}

// Converts a String (expected to be a syllable) to kana.
fn convert_syllable(d: &Dict, ow: &String) -> String {
    // <pingveno> Because String impls Borrow<str>
    // `&ow.to_string()` => `ow`
    match d.get(ow) {
        Some(c) => c.clone(),
        None => ow.clone(),
    }
}
<|endoftext|>


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

#![crate_name = "skia"]
#![crate_type = "rlib"]

#![feature(globs)]

extern crate libc;

pub use skia::{
    SkiaSkNativeSharedGLContextRef,
    SkiaGrContextRef,
    SkiaGrGLSharedSurfaceRef,
    SkiaGrGLNativeContextRef,
    SkiaSkNativeSharedGLContextCreate,
    SkiaSkNativeSharedGLContextRetain,
    SkiaSkNativeSharedGLContextRelease,
    SkiaSkNativeSharedGLContextGetFBOID,
    SkiaSkNativeSharedGLContextStealSurface,
    SkiaSkNativeSharedGLContextGetGrContext,
    SkiaSkNativeSharedGLContextMakeCurrent,
    SkiaSkNativeSharedGLContextFlush,
};

pub mod skia;
<commit_msg>Upgrade to rustc 1.0.0-nightly (1d00c545e 2015-01-30 19:56:34 +0000)<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/. */

#![crate_name = "skia"]
#![crate_type = "rlib"]

#![feature(libc)]

extern crate libc;

pub use skia::{
    SkiaSkNativeSharedGLContextRef,
    SkiaGrContextRef,
    SkiaGrGLSharedSurfaceRef,
    SkiaGrGLNativeContextRef,
    SkiaSkNativeSharedGLContextCreate,
    SkiaSkNativeSharedGLContextRetain,
    SkiaSkNativeSharedGLContextRelease,
    SkiaSkNativeSharedGLContextGetFBOID,
    SkiaSkNativeSharedGLContextStealSurface,
    SkiaSkNativeSharedGLContextGetGrContext,
    SkiaSkNativeSharedGLContextMakeCurrent,
    SkiaSkNativeSharedGLContextFlush,
};

pub mod skia;
<|endoftext|>


<commit_before>//! Does all the magic to have you potentially long output piped through the
//! external pager. Similar to what git does for its output.
//!
//! # Quick Start
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::new().setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Under the hood this forks the current process, connects child' stdout
//! to parent's stdin, and then replaces the parent with the pager of choice
//! (environment variable PAGER). The child just continues as normal. If PAGER
//! environment variable is not present `Pager` probes current PATH for `more`.
//! If found it is used as a default pager.
//!
//! You can control pager to a limited degree. For example you can change the
//! environment variable used for finding pager executable.
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::env("MY_PAGER").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! If no suitable pager found `setup()` does nothing and your executable keeps
//! running as usual. `Pager` cleans after itself and doesn't leak resources in
//! case of setup failure.
//!
//! If you need to disable pager altogether set environment variable `NOPAGER` and `Pager::setup()`
//! will skip initialization. The host application will continue as normal. `Pager::is_on()` will
//! reflect the fact that no Pager is active.

extern crate errno;
extern crate libc;

mod utils;

use std::ffi::OsString;

const DEFAULT_PAGER_ENV: &str = "PAGER";

#[derive(Debug, Default)]
pub struct Pager {
    pager: Option<OsString>,
    env: Option<String>,
    on: bool,
}

impl Pager {
    /// Creates new instance of pager with default settings
    pub fn new() -> Self {
        Pager::env(DEFAULT_PAGER_ENV)
    }

    /// Creates new instance of pager using `env` environment variable instead of PAGER
    pub fn env(env: &str) -> Self {
        let pager = utils::find_pager(env);

        Pager {
            pager: pager,
            env: String::from(env).into(),
            on: true,
        }
    }

    /// Gives quick assessment of successful Pager setup
    pub fn is_on(&self) -> bool {
        self.on
    }

    /// Initiates Pager framework and sets up all the necessary environment for sending standard
    /// output to the activated pager.
    pub fn setup(&mut self) {
        if let Some(ref pager) = self.pager {
            let (pager_stdin, main_stdout) = utils::pipe();
            let pid = utils::fork();
            match pid {
                -1 => {
                    // Fork failed
                    utils::close(pager_stdin);
                    utils::close(main_stdout);
                    self.on = false
                }
                0 => {
                    // I am child
                    utils::dup2(main_stdout, libc::STDOUT_FILENO);
                    utils::close(pager_stdin);
                }
                _ => {
                    // I am parent
                    utils::dup2(pager_stdin, libc::STDIN_FILENO);
                    utils::close(main_stdout);
                    utils::execvp(pager);
                }
            }
        }
    }
}
<commit_msg>Add Pager::with_pager()<commit_after>//! Does all the magic to have you potentially long output piped through the
//! external pager. Similar to what git does for its output.
//!
//! # Quick Start
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::new().setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Under the hood this forks the current process, connects child' stdout
//! to parent's stdin, and then replaces the parent with the pager of choice
//! (environment variable PAGER). The child just continues as normal. If PAGER
//! environment variable is not present `Pager` probes current PATH for `more`.
//! If found it is used as a default pager.
//!
//! You can control pager to a limited degree. For example you can change the
//! environment variable used for finding pager executable.
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::env("MY_PAGER").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Alternatively you can specify directly the desired pager command, exactly
//! as it would appear in PAGER environment variable. This is useful if you
//! need some specific pager and/or flags (like "more -r") and would like to
//! avoid forcing your consumers into modifying their existing PAGER
//! configuration just for your application.
//!
//! ```rust
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::with_pager("more -r").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! If no suitable pager found `setup()` does nothing and your executable keeps
//! running as usual. `Pager` cleans after itself and doesn't leak resources in
//! case of setup failure.
//!
//! If you need to disable pager altogether set environment variable `NOPAGER` and `Pager::setup()`
//! will skip initialization. The host application will continue as normal. `Pager::is_on()` will
//! reflect the fact that no Pager is active.

extern crate errno;
extern crate libc;

mod utils;

use std::ffi::OsString;

const DEFAULT_PAGER_ENV: &str = "PAGER";

#[derive(Debug, Default)]
pub struct Pager {
    pager: Option<OsString>,
    env: Option<String>,
    on: bool,
}

impl Pager {
    /// Creates new instance of pager with default settings
    pub fn new() -> Self {
        Pager::env(DEFAULT_PAGER_ENV)
    }

    /// Creates new instance of pager using `env` environment variable instead of PAGER
    pub fn env(env: &str) -> Self {
        let pager = utils::find_pager(env);

        Pager {
            pager: pager,
            env: String::from(env).into(),
            on: true,
        }
    }

    /// Creates a new pager instance directly specifying the desired pager
    pub fn with_pager(pager: &str) -> Self {
        Pager {
            pager: OsString::from(pager).into(),
            env: None,
            on: true,
        }
    }

    /// Gives quick assessment of successful Pager setup
    pub fn is_on(&self) -> bool {
        self.on
    }

    /// Initiates Pager framework and sets up all the necessary environment for sending standard
    /// output to the activated pager.
    pub fn setup(&mut self) {
        if let Some(ref pager) = self.pager {
            let (pager_stdin, main_stdout) = utils::pipe();
            let pid = utils::fork();
            match pid {
                -1 => {
                    // Fork failed
                    utils::close(pager_stdin);
                    utils::close(main_stdout);
                    self.on = false
                }
                0 => {
                    // I am child
                    utils::dup2(main_stdout, libc::STDOUT_FILENO);
                    utils::close(pager_stdin);
                }
                _ => {
                    // I am parent
                    utils::dup2(pager_stdin, libc::STDIN_FILENO);
                    utils::close(main_stdout);
                    utils::execvp(pager);
                }
            }
        }
    }
}
<|endoftext|>