<commit_before>#![no_std]
//!
//! You can populate [`Petnames`] with your own word lists, but the word lists
//! from upstream [petname](https://github.com/dustinkirkland/petname) are
//! included with the `default_dictionary` feature (enabled by default). See
//! [`Petnames::small`], [`Petnames::medium`], and [`Petnames::large`] to select
//! a particular built-in word list, or use the [`Default`] implementation.
//!
//! The other thing you need is a random number generator from [rand][]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let pname = petname::Petnames::default().generate(&mut rng, 7, ":");
//! ```
//!
//! It may be more convenient to use the default random number generator:
//!
//! ```rust
//! let pname = petname::Petnames::default().generate_one(7, ":");
//! ```
//!
//! There's a [convenience function][petname] that'll do all of this:
//!
//! ```rust
//! let pname = petname::petname(7, ":");
//! ```
//!
//! But the most flexible approach is to create an [`Iterator`] with
//! [`iter`][`Petnames::iter`]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let petnames = petname::Petnames::default();
//! let ten_thousand_names: Vec<String> =
//!   petnames.iter(&mut rng, 3, "_").take(10000).collect();
//! ```
//!
//! You can modify the word lists to, for example, only use words beginning with
//! the letter "b":
//!
//! ```rust
//! let mut petnames = petname::Petnames::default();
//! petnames.retain(|s| s.starts_with("b"));
//! petnames.generate_one(3, ".");
//! ```
//!

extern crate alloc;

use alloc::{
    string::{String, ToString},
    vec::Vec,
};

use itertools::Itertools;
use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
#[cfg(feature = "std_rng")]
#[cfg(feature = "default_dictionary")]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::new().generate_one(words, separator)
}

/// A word list.
pub type Words<'a> = Vec<&'a str>;

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * `n - 2` adverbs when `n >= 2`, otherwise 0 adverbs.
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * 1 name / noun when `n >= 1`, otherwise 0 names.
///
#[derive(Clone, Debug, PartialEq)]
pub struct Petnames<'a> {
    pub adjectives: Words<'a>,
    pub adverbs: Words<'a>,
    pub names: Words<'a>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn new() -> Self {
        Self::default()
    }

    /// Constructs a new `Petnames` from the small word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(feature = "default_dictionary")]
    /// let mut petnames = petname::Petnames::default();
    /// # #[cfg(feature = "default_dictionary")]
    /// petnames.retain(|s| s.starts_with("b"));
    /// # #[cfg(feature = "default_dictionary")]
    /// # #[cfg(feature = "std_rng")]
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, mut predicate: F)
    where
        F: FnMut(&str) -> bool,
    {
        self.adjectives.retain(|word| predicate(word));
        self.adverbs.retain(|word| predicate(word));
        self.names.retain(|word| predicate(word));
    }

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        Lists(self, words)
            .map(|list| list.len() as u128)
            .fold1(u128::saturating_mul)
            .unwrap_or(0u128)
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Notes
    ///
    /// This may return fewer words than you request if one or more of the word
    /// lists are empty. For example, if there are no adverbs, requesting 3 or
    /// more words may still yield only "doubtful-salmon".
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        itertools::Itertools::intersperse(
            Lists(self, words)
                .filter_map(|list| list.choose(rng))
                .cloned(),
            separator,
        )
        .collect::<String>()
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    #[cfg(feature = "std_rng")]
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }

    /// Iterator yielding petnames.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let petnames = petname::Petnames::default();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut iter = petnames.iter(&mut rng, 4, "_");
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// println!("name: {}", iter.next().unwrap());
    /// ```
    ///
    pub fn iter<RNG>(&self, rng: &'a mut RNG, words: u8, separator: &str) -> Names<RNG>
    where
        RNG: rand::Rng,
    {
        Names {
            petnames: self,
            rng,
            words,
            separator: separator.to_string(),
        }
    }

    /// Iterator yielding unique – i.e. non-repeating – petnames.
    pub fn iter_unique<RNG>(
        &'a self,
        rng: &'a mut RNG,
        words: u8,
        separator: &str,
    ) -> NamesUnique<'a, core::iter::Cycle<alloc::vec::IntoIter<&'a str>>>
    where
        RNG: rand::Rng,
    {
        NamesUnique {
            iters: Lists(self, words)
                .cloned()
                .map(|mut list| {
                    list.shuffle(rng); // Could be expensive.
                    list.push(""); // Cycle marker.
                    (list.into_iter().cycle(), None)
                })
                .collect(),
            separator: separator.to_string(),
        }
    }
}

#[cfg(feature = "default_dictionary")]
impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::small()
    }
}

/// Iterator over a `Petnames`' word lists.
///
/// This yields the appropriate lists from which to select a word when
/// constructing a petname of `n` words. For example, if you want 3 words in
/// your petname, this will first yield the adverbs word list, then adjectives,
/// then names.
struct Lists<'a>(&'a Petnames<'a>, u8);

impl<'a> Iterator for Lists<'a> {
    type Item = &'a Words<'a>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.1 as usize))
    }

    fn next(&mut self) -> Option<Self::Item> {
        let Self(petnames, ref mut word) = self;
        match word {
            0 => None,
            1 => {
                *word -= 1;
                Some(&petnames.names)
            }
            2 => {
                *word -= 1;
                Some(&petnames.adjectives)
            }
            _ => {
                *word -= 1;
                Some(&petnames.adverbs)
            }
        }
    }
}

/// Iterator yielding petnames.
pub struct Names<'a, RNG>
where
    RNG: rand::Rng,
{
    petnames: &'a Petnames<'a>,
    rng: &'a mut RNG,
    words: u8,
    separator: String,
}

impl<'a, RNG> Names<'a, RNG>
where
    RNG: rand::Rng,
{
    /// Calculate the cardinality of this iterator; see `Petnames::cardinality`.
    #[allow(dead_code)]
    pub fn cardinality(&self) -> u128 {
        self.petnames.cardinality(self.words)
    }
}

impl<'a, RNG> Iterator for Names<'a, RNG>
where
    RNG: rand::Rng,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        Some(
            self.petnames
                .generate(self.rng, self.words, &self.separator),
        )
    }
}

/// Iterator yielding unique petnames.
pub struct NamesUnique<'a, ITERATOR>
where
    ITERATOR: Iterator<Item = &'a str>,
{
    iters: Vec<(ITERATOR, Option<ITERATOR::Item>)>,
    separator: String,
}

impl<'a> NamesUnique<'a, core::iter::Cycle<alloc::vec::IntoIter<&'a str>>> {
    pub fn new<RNG>(lists: &[&'a Words<'a>], rng: &'a mut RNG, separator: &str) -> Self
    where
        RNG: rand::Rng,
    {
        Self {
            iters: lists
                .iter()
                .cloned()
                .cloned()
                .map(|mut list| {
                    list.shuffle(rng); // Could be expensive.
                    list.push(""); // Cycle marker.
                    (list.into_iter().cycle(), None)
                })
                .collect(),
            separator: separator.to_string(),
        }
    }
}

impl<'a, ITERATOR> Iterator for NamesUnique<'a, ITERATOR>
where
    ITERATOR: Iterator<Item = &'a str>,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        let mut bump = true; // Request advance of next iterator.
        for (iter, word) in self.iters.iter_mut() {
            if bump || word.is_none() {
                match iter.next() {
                    None => {
                        // This shouldn't happen because we expect the iterators
                        // to cycle. However, if it does, we're definitely done.
                        return None;
                    }
                    Some("") => {
                        // This is the cycle end marker. We want to get another
                        // new word from this iterator, and advance the *next*
                        // iterator too.
                        match iter.next() {
                            None => return None,
                            Some("") => return None,
                            Some(s) => *word = Some(s),
                        }
                        bump = true
                    }
                    Some(s) => {
                        // We have a new word from this iterator, so we do not
                        // yet need to advance the next iterator.
                        *word = Some(s);
                        bump = false
                    }
                }
            }
        }
        if bump {
            // We reached the end of the last iterator, hence we're done.
            None
        } else {
            // We can construct a word!
            Some(
                itertools::Itertools::intersperse(
                    self.iters.iter().filter_map(|(_, w)| *w),
                    &self.separator,
                )
                .collect(),
            )
        }
    }
}
<commit_msg>Rename NamesUnique to NamesProduct, and use in iter_unique<commit_after>#![no_std]
//!
//! You can populate [`Petnames`] with your own word lists, but the word lists
//! from upstream [petname](https://github.com/dustinkirkland/petname) are
//! included with the `default_dictionary` feature (enabled by default). See
//! [`Petnames::small`], [`Petnames::medium`], and [`Petnames::large`] to select
//! a particular built-in word list, or use the [`Default`] implementation.
//!
//! The other thing you need is a random number generator from [rand][]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let pname = petname::Petnames::default().generate(&mut rng, 7, ":");
//! ```
//!
//! It may be more convenient to use the default random number generator:
//!
//! ```rust
//! let pname = petname::Petnames::default().generate_one(7, ":");
//! ```
//!
//! There's a [convenience function][petname] that'll do all of this:
//!
//! ```rust
//! let pname = petname::petname(7, ":");
//! ```
//!
//! But the most flexible approach is to create an [`Iterator`] with
//! [`iter`][`Petnames::iter`]:
//!
//! ```rust
//! let mut rng = rand::thread_rng();
//! let petnames = petname::Petnames::default();
//! let ten_thousand_names: Vec<String> =
//!   petnames.iter(&mut rng, 3, "_").take(10000).collect();
//! ```
//!
//! You can modify the word lists to, for example, only use words beginning with
//! the letter "b":
//!
//! ```rust
//! let mut petnames = petname::Petnames::default();
//! petnames.retain(|s| s.starts_with("b"));
//! petnames.generate_one(3, ".");
//! ```
//!

extern crate alloc;

use alloc::{
    string::{String, ToString},
    vec::Vec,
};

use itertools::Itertools;
use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
#[cfg(feature = "std_rng")]
#[cfg(feature = "default_dictionary")]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::new().generate_one(words, separator)
}

/// A word list.
pub type Words<'a> = Vec<&'a str>;

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * `n - 2` adverbs when `n >= 2`, otherwise 0 adverbs.
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * 1 name / noun when `n >= 1`, otherwise 0 names.
///
#[derive(Clone, Debug, PartialEq)]
pub struct Petnames<'a> {
    pub adjectives: Words<'a>,
    pub adverbs: Words<'a>,
    pub names: Words<'a>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn new() -> Self {
        Self::default()
    }

    /// Constructs a new `Petnames` from the small word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    #[cfg(feature = "default_dictionary")]
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(feature = "default_dictionary")]
    /// let mut petnames = petname::Petnames::default();
    /// # #[cfg(feature = "default_dictionary")]
    /// petnames.retain(|s| s.starts_with("b"));
    /// # #[cfg(feature = "default_dictionary")]
    /// # #[cfg(feature = "std_rng")]
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, mut predicate: F)
    where
        F: FnMut(&str) -> bool,
    {
        self.adjectives.retain(|word| predicate(word));
        self.adverbs.retain(|word| predicate(word));
        self.names.retain(|word| predicate(word));
    }

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    pub fn cardinality(&self, words: u8) -> u128 {
        Lists(self, words)
            .map(|list| list.len() as u128)
            .fold1(u128::saturating_mul)
            .unwrap_or(0u128)
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Notes
    ///
    /// This may return fewer words than you request if one or more of the word
    /// lists are empty. For example, if there are no adverbs, requesting 3 or
    /// more words may still yield only "doubtful-salmon".
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        itertools::Itertools::intersperse(
            Lists(self, words)
                .filter_map(|list| list.choose(rng))
                .cloned(),
            separator,
        )
        .collect::<String>()
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    #[cfg(feature = "std_rng")]
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }

    /// Iterator yielding petnames.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut rng = rand::thread_rng();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let petnames = petname::Petnames::default();
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// let mut iter = petnames.iter(&mut rng, 4, "_");
    /// # #[cfg(all(feature = "std_rng", feature = "default_dictionary"))]
    /// println!("name: {}", iter.next().unwrap());
    /// ```
    ///
    pub fn iter<RNG>(&self, rng: &'a mut RNG, words: u8, separator: &str) -> Names<RNG>
    where
        RNG: rand::Rng,
    {
        Names {
            petnames: self,
            rng,
            words,
            separator: separator.to_string(),
        }
    }

    /// Iterator yielding unique – i.e. non-repeating – petnames.
    pub fn iter_unique<RNG>(
        &'a self,
        rng: &'a mut RNG,
        words: u8,
        separator: &str,
    ) -> NamesProduct<'a, core::iter::Cycle<alloc::vec::IntoIter<&'a str>>>
    where
        RNG: rand::Rng,
    {
        let lists: Vec<Words<'a>> = Lists(self, words).cloned().collect();
        NamesProduct::new(&lists, rng, separator)
    }
}

#[cfg(feature = "default_dictionary")]
impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::small()
    }
}

/// Iterator over a `Petnames`' word lists.
///
/// This yields the appropriate lists from which to select a word when
/// constructing a petname of `n` words. For example, if you want 3 words in
/// your petname, this will first yield the adverbs word list, then adjectives,
/// then names.
struct Lists<'a>(&'a Petnames<'a>, u8);

impl<'a> Iterator for Lists<'a> {
    type Item = &'a Words<'a>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.1 as usize))
    }

    fn next(&mut self) -> Option<Self::Item> {
        let Self(petnames, ref mut word) = self;
        match word {
            0 => None,
            1 => {
                *word -= 1;
                Some(&petnames.names)
            }
            2 => {
                *word -= 1;
                Some(&petnames.adjectives)
            }
            _ => {
                *word -= 1;
                Some(&petnames.adverbs)
            }
        }
    }
}

/// Iterator yielding petnames.
pub struct Names<'a, RNG>
where
    RNG: rand::Rng,
{
    petnames: &'a Petnames<'a>,
    rng: &'a mut RNG,
    words: u8,
    separator: String,
}

impl<'a, RNG> Names<'a, RNG>
where
    RNG: rand::Rng,
{
    /// Calculate the cardinality of this iterator; see `Petnames::cardinality`.
    #[allow(dead_code)]
    pub fn cardinality(&self) -> u128 {
        self.petnames.cardinality(self.words)
    }
}

impl<'a, RNG> Iterator for Names<'a, RNG>
where
    RNG: rand::Rng,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        Some(
            self.petnames
                .generate(self.rng, self.words, &self.separator),
        )
    }
}

/// Iterator yielding unique petnames.
pub struct NamesProduct<'a, ITERATOR>
where
    ITERATOR: Iterator<Item = &'a str>,
{
    iters: Vec<(ITERATOR, Option<ITERATOR::Item>)>,
    separator: String,
}

impl<'a> NamesProduct<'a, core::iter::Cycle<alloc::vec::IntoIter<&'a str>>> {
    pub fn new<RNG>(lists: &[Words<'a>], rng: &'a mut RNG, separator: &str) -> Self
    where
        RNG: rand::Rng,
    {
        NamesProduct {
            iters: lists
                .iter()
                .cloned()
                .map(|mut list| {
                    list.shuffle(rng); // Could be expensive.
                    list.push(""); // Cycle marker.
                    (list.into_iter().cycle(), None)
                })
                .collect(),
            separator: separator.to_string(),
        }
    }
}

impl<'a, ITERATOR> Iterator for NamesProduct<'a, ITERATOR>
where
    ITERATOR: Iterator<Item = &'a str>,
{
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        let mut bump = true; // Request advance of next iterator.
        for (iter, word) in self.iters.iter_mut() {
            if bump || word.is_none() {
                match iter.next() {
                    None => {
                        // This shouldn't happen because we expect the iterators
                        // to cycle. However, if it does, we're definitely done.
                        return None;
                    }
                    Some("") => {
                        // This is the cycle end marker. We want to get another
                        // new word from this iterator, and advance the *next*
                        // iterator too.
                        match iter.next() {
                            None => return None,
                            Some("") => return None,
                            Some(s) => *word = Some(s),
                        }
                        bump = true
                    }
                    Some(s) => {
                        // We have a new word from this iterator, so we do not
                        // yet need to advance the next iterator.
                        *word = Some(s);
                        bump = false
                    }
                }
            }
        }
        if bump {
            // We reached the end of the last iterator, hence we're done.
            None
        } else {
            // We can construct a word!
            Some(
                itertools::Itertools::intersperse(
                    self.iters.iter().filter_map(|(_, w)| *w),
                    &self.separator,
                )
                .collect(),
            )
        }
    }
}
<|endoftext|>


<commit_before>use std::convert::Into;
use std::str::FromStr;

const BYTE: i64     = 1;
const KILOBYTE: i64 = BYTE     << 10;
const MEGABYTE: i64 = KILOBYTE << 10;
const GIGABYTE: i64 = MEGABYTE << 10;
const TERABYTE: i64 = GIGABYTE << 10;
const PETABYTE: i64 = TERABYTE << 10;
const EXABYTE: i64  = PETABYTE << 10;

macro_rules! map(
  { $($key:expr => $value:expr),+ } => {
    {
      let mut m = ::std::collections::HashMap::new();
      $(
        m.insert($key, $value);
        )+
        m
    }
  };
);

pub trait Capacity {

  fn bytes(&self) -> i64;

  fn kilobytes(&self) -> i64 {
    self.bytes().rotate_left(10)
  }

  fn megabytes(&self) -> i64 {
    self.kilobytes().rotate_left(10)
  }

  fn gigabytes(&self) -> i64 {
    self.megabytes().rotate_left(10)
  }

  fn terabytes(&self) -> i64 {
    self.gigabytes().rotate_left(10)
  }

  fn petabytes(&self) -> i64 {
    self.terabytes().rotate_left(10)
  }

  fn exabytes(&self) -> i64 {
    self.petabytes().rotate_left(10)
  }

  fn capacity(&self) -> String {
    match self.bytes() {
      small if small < KILOBYTE =>
        stringify!(small).to_owned(),
      large => {
        let units = vec![
          ('E', EXABYTE),
          ('P', PETABYTE),
          ('T', TERABYTE),
          ('G', GIGABYTE),
          ('M', MEGABYTE),
          ('K', KILOBYTE)
        ];
        for (suffix, size) in units {
          if large == size {
            return format!("1{}", suffix)
          } else if large > size {
            let sized = (large as f64) / (size as f64);
            let round = (sized * 100.0).round() / 100.0;
            return format!("{:.1}{}", round, suffix)
          }
        }
        unreachable!()
      }
    }
  }
}

impl Capacity for i64 {
  fn bytes(&self) -> i64 {
    *self
  }
}

impl Capacity for Bytes {
  fn bytes(&self) -> i64 {
    (*self).size
  }
}

#[derive(Debug)]
pub struct Bytes {
  size: i64
}

impl Into<Bytes> for i64 {
  fn into(self) -> Bytes {
    Bytes { size: self }
  }
}

impl FromStr for Bytes {
  type Err = String;
  fn from_str(s: &str) -> Result<Bytes, String> {
    let units = map!(
      'E' => EXABYTE,
      'P' => PETABYTE,
      'T' => TERABYTE,
      'G' => GIGABYTE,
      'M' => MEGABYTE,
      'K' => KILOBYTE
    );
    let len = s.len();
    if len > 1 {
      let last = s.chars().last().unwrap();
      match units.get(&last) {
        Some(unit) => {
          let init: String = s.chars().take(s.chars().count() - 1).collect();
          init.parse::<i64>().map(|lit| {
            Bytes { size: lit * unit }
          }).or_else(|_| Err(s.to_owned()))
        },
        _ => {
          Err(s.to_owned())
        }
      }
    } else {
      s.parse::<i64>().map(|lit| {
        Bytes { size: lit }
      }).or_else(|_| Err(s.to_owned()))
    }
  }
}

#[test]
fn test_bytes() {
  assert_eq!(1.bytes(), 1);
}

#[test]
fn test_kilobytes() {
  assert_eq!(1.kilobytes(), 1024)
}

#[test]
fn test_megabytes() {
  assert_eq!(1.megabytes(), 1048576)
}

#[test]
fn test_gigabytes() {
  assert_eq!(1.gigabytes(), 1073741824)
}

#[test]
fn test_terabytes() {
  assert_eq!(1.terabytes(), 1099511627776)
}

#[test]
fn test_petabytes() {
  assert_eq!(1.petabytes(), 1125899906842624)
}

#[test]
fn test_exabytes() {
  assert_eq!(1.exabytes(), 1152921504606846976)
}

#[test]
fn test_kilobytes_capactity() {
  let half = 1.kilobytes() / 2;
  assert_eq!((1.kilobytes() + half).capacity(), "1.5K".to_owned())
}

#[test]
fn test_megabytes_capactity() {
  let half = 1.megabytes() / 2;
  assert_eq!((1.megabytes() + half).capacity(), "1.5M".to_owned())
}

#[test]
fn test_gigabytes_capactity() {
  let half = 1.gigabytes() / 2;
  assert_eq!((1.gigabytes() + half).capacity(), "1.5G".to_owned())
}

#[test]
fn test_terabytes_capactity() {
  let half = 1.terabytes() / 2;
  assert_eq!((1.terabytes() + half).capacity(), "1.5T".to_owned())
}

#[test]
fn test_petabytes_capactity() {
  let half = 1.petabytes() / 2;
  assert_eq!((1.petabytes() + half).capacity(), "1.5P".to_owned())
}

#[test]
fn test_exabytes_capactity() {
  let half = 1.exabytes() / 2;
  assert_eq!((1.exabytes() + half).capacity(), "1.5E".to_owned())
}

#[test]
fn test_kilobytes_parse() {
  let cap: String = 1.kilobytes().capacity();
  let bytes = cap.parse::<Bytes>().ok().unwrap();
  assert_eq!(bytes.size.capacity(), cap)
}
<commit_msg>less vars<commit_after>use std::convert::Into;
use std::str::FromStr;

const BYTE: i64     = 1;
const KILOBYTE: i64 = BYTE     << 10;
const MEGABYTE: i64 = KILOBYTE << 10;
const GIGABYTE: i64 = MEGABYTE << 10;
const TERABYTE: i64 = GIGABYTE << 10;
const PETABYTE: i64 = TERABYTE << 10;
const EXABYTE: i64  = PETABYTE << 10;

macro_rules! map(
  { $($key:expr => $value:expr),+ } => {
    {
      let mut m = ::std::collections::HashMap::new();
      $(
        m.insert($key, $value);
        )+
        m
    }
  };
);

pub trait Capacity {

  fn bytes(&self) -> i64;

  fn kilobytes(&self) -> i64 {
    self.bytes().rotate_left(10)
  }

  fn megabytes(&self) -> i64 {
    self.kilobytes().rotate_left(10)
  }

  fn gigabytes(&self) -> i64 {
    self.megabytes().rotate_left(10)
  }

  fn terabytes(&self) -> i64 {
    self.gigabytes().rotate_left(10)
  }

  fn petabytes(&self) -> i64 {
    self.terabytes().rotate_left(10)
  }

  fn exabytes(&self) -> i64 {
    self.petabytes().rotate_left(10)
  }

  fn capacity(&self) -> String {
    match self.bytes() {
      small if small < KILOBYTE =>
        stringify!(small).to_owned(),
      large => {
        let units = vec![
          ('E', EXABYTE),
          ('P', PETABYTE),
          ('T', TERABYTE),
          ('G', GIGABYTE),
          ('M', MEGABYTE),
          ('K', KILOBYTE)
        ];
        for (suffix, size) in units {
          if large == size {
            return format!("1{}", suffix)
          } else if large > size {
            let sized = (large as f64) / (size as f64);
            let round = (sized * 100.0).round() / 100.0;
            return format!("{:.1}{}", round, suffix)
          }
        }
        unreachable!()
      }
    }
  }
}

impl Capacity for i64 {
  fn bytes(&self) -> i64 {
    *self
  }
}

impl Capacity for Bytes {
  fn bytes(&self) -> i64 {
    (*self).size
  }
}

#[derive(Debug)]
pub struct Bytes {
  size: i64
}

impl Into<Bytes> for i64 {
  fn into(self) -> Bytes {
    Bytes { size: self }
  }
}

impl FromStr for Bytes {
  type Err = String;
  fn from_str(s: &str) -> Result<Bytes, String> {
    let units = map!(
      'E' => EXABYTE,
      'P' => PETABYTE,
      'T' => TERABYTE,
      'G' => GIGABYTE,
      'M' => MEGABYTE,
      'K' => KILOBYTE
    );
    if s.len() > 1 {
      let last = s.chars().last().unwrap();
      match units.get(&last) {
        Some(unit) => {
          let init: String = s.chars().take(s.chars().count() - 1).collect();
          init.parse::<i64>().map(|lit| {
            Bytes { size: lit * unit }
          }).or_else(|_| Err(s.to_owned()))
        },
        _ => {
          Err(s.to_owned())
        }
      }
    } else {
      s.parse::<i64>().map(|lit| {
        Bytes { size: lit }
      }).or_else(|_| Err(s.to_owned()))
    }
  }
}

#[test]
fn test_bytes() {
  assert_eq!(1.bytes(), 1);
}

#[test]
fn test_kilobytes() {
  assert_eq!(1.kilobytes(), 1024)
}

#[test]
fn test_megabytes() {
  assert_eq!(1.megabytes(), 1048576)
}

#[test]
fn test_gigabytes() {
  assert_eq!(1.gigabytes(), 1073741824)
}

#[test]
fn test_terabytes() {
  assert_eq!(1.terabytes(), 1099511627776)
}

#[test]
fn test_petabytes() {
  assert_eq!(1.petabytes(), 1125899906842624)
}

#[test]
fn test_exabytes() {
  assert_eq!(1.exabytes(), 1152921504606846976)
}

#[test]
fn test_kilobytes_capactity() {
  let half = 1.kilobytes() / 2;
  assert_eq!((1.kilobytes() + half).capacity(), "1.5K".to_owned())
}

#[test]
fn test_megabytes_capactity() {
  let half = 1.megabytes() / 2;
  assert_eq!((1.megabytes() + half).capacity(), "1.5M".to_owned())
}

#[test]
fn test_gigabytes_capactity() {
  let half = 1.gigabytes() / 2;
  assert_eq!((1.gigabytes() + half).capacity(), "1.5G".to_owned())
}

#[test]
fn test_terabytes_capactity() {
  let half = 1.terabytes() / 2;
  assert_eq!((1.terabytes() + half).capacity(), "1.5T".to_owned())
}

#[test]
fn test_petabytes_capactity() {
  let half = 1.petabytes() / 2;
  assert_eq!((1.petabytes() + half).capacity(), "1.5P".to_owned())
}

#[test]
fn test_exabytes_capactity() {
  let half = 1.exabytes() / 2;
  assert_eq!((1.exabytes() + half).capacity(), "1.5E".to_owned())
}

#[test]
fn test_kilobytes_parse() {
  let cap: String = 1.kilobytes().capacity();
  let bytes = cap.parse::<Bytes>().ok().unwrap();
  assert_eq!(bytes.size.capacity(), cap)
}
<|endoftext|>


<commit_before>//! Colors writable type characters with the ascii rainbow
//!
//! You can use this any type that requires a `io::Write` type
//!
//! # examples
//!
//! ```rust
//! use std::io::Write;
//! write!(
//!   &mut rainbowcoat::stdout(),
//!   "hello rainbow"
//! );
//! ```
extern crate  ansi_term;

use std::f64::consts::PI;
use std::io::{self, Stdout, Write};

use ansi_term::Color;

/// Colors writable type characters with the ascii rainbow
///
/// You can use this any type that requires a `io::Write` type
///
/// # examples
///
/// ```rust
/// use std::io::Write;
/// write!(
///   &mut rainbowcoat::stdout(),
///   "hello rainbow"
/// );
/// ```
pub struct Colors<W> {
    wrapped: W,
    spread: f64,
    frequency: f64,
    seed: f64,
}

/// Convenience function that wraps `std::io::Stdout` in a`Colors` instance
pub fn stdout() -> Colors<Stdout> {
    Colors::new(io::stdout())
}

impl<W> Colors<W> {
    /// Creates a new `Colors` instance with default spread of `3.0`,
    /// frequency of `0.1` and seed valud of `0.0`
    pub fn new(wrapped: W) -> Self {
        Self::configure(wrapped, 3.0, 0.1, 0.0)
    }

    /// Creates a more configurable instance with provided params
    pub fn configure(wrapped: W, spread: f64, frequency: f64, seed: f64) -> Self {
        Self {
            wrapped,
            spread,
            frequency,
            seed,
        }
    }

    fn color(&mut self, seed: f64) -> Color {
        let i = self.frequency * seed / self.spread;
        let red = i.sin() * 127.00 + 128.00;
        let green = (i + (PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
        let blue = (i + (PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;
        Color::RGB(red as u8, green as u8, blue as u8)
    }
}

impl<W: Write> Write for Colors<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        for line in ::std::str::from_utf8(buf).unwrap().lines() {
            let mut seed = self.seed;
            for c in line.chars() {
                seed += 1.0;
                // fixme: Color#paint doesn't work with scalar char types
                let mut s = String::with_capacity(1);
                s.push(c);
                let color = self.color(seed);
                write!(&mut self.wrapped, "{}", color.paint(s))?
            }
            write!(&mut self.wrapped, "\n")?;
        }
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        self.wrapped.flush()
    }
}

#[cfg(test)]
mod tests {
    use super::Colors;
    use ansi_term::Color;
    use std::io;
    #[test]
    fn colors_colors() {
        assert_eq!(Colors::new(io::sink()).color(0.0), Color::RGB(128, 237, 18))
    }
}
<commit_msg>increase test cov<commit_after>//! Colors writable type characters with the ascii rainbow
//!
//! You can use this any type that requires a `io::Write` type
//!
//! # examples
//!
//! ```rust
//! use std::io::Write;
//! write!(
//!   &mut rainbowcoat::stdout(),
//!   "hello rainbow"
//! );
//! ```
extern crate  ansi_term;

use std::f64::consts::PI;
use std::io::{self, Stdout, Write};

use ansi_term::Color;

/// Colors writable type characters with the ascii rainbow
///
/// You can use this any type that requires a `io::Write` type
///
/// # examples
///
/// ```rust
/// use std::io::Write;
/// write!(
///   &mut rainbowcoat::stdout(),
///   "hello rainbow"
/// );
/// ```
pub struct Colors<W> {
    wrapped: W,
    spread: f64,
    frequency: f64,
    seed: f64,
}

/// Convenience function that wraps `std::io::Stdout` in a`Colors` instance
pub fn stdout() -> Colors<Stdout> {
    Colors::new(io::stdout())
}

impl<W> Colors<W> {
    /// Creates a new `Colors` instance with default spread of `3.0`,
    /// frequency of `0.1` and seed valud of `0.0`
    pub fn new(wrapped: W) -> Self {
        Self::configure(wrapped, 3.0, 0.1, 0.0)
    }

    /// Creates a more configurable instance with provided params
    pub fn configure(wrapped: W, spread: f64, frequency: f64, seed: f64) -> Self {
        Self {
            wrapped,
            spread,
            frequency,
            seed,
        }
    }

    fn color(&mut self, seed: f64) -> Color {
        let i = self.frequency * seed / self.spread;
        let red = i.sin() * 127.00 + 128.00;
        let green = (i + (PI * 2.00 / 3.00)).sin() * 127.00 + 128.00;
        let blue = (i + (PI * 4.00 / 3.00)).sin() * 127.00 + 128.00;
        Color::RGB(red as u8, green as u8, blue as u8)
    }
}

impl<W: Write> Write for Colors<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        for line in ::std::str::from_utf8(buf).unwrap().lines() {
            let mut seed = self.seed;
            for c in line.chars() {
                seed += 1.0;
                // fixme: Color#paint doesn't work with scalar char types
                let mut s = String::with_capacity(1);
                s.push(c);
                let color = self.color(seed);
                write!(&mut self.wrapped, "{}", color.paint(s))?
            }
            write!(&mut self.wrapped, "\n")?;
        }
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        self.wrapped.flush()
    }
}

#[cfg(test)]
mod tests {
    use super::Colors;
    use ansi_term::Color;
    use std::io::{self, Write};

    #[test]
    fn colors_colors() {
        assert_eq!(Colors::new(io::sink()).color(0.0), Color::RGB(128, 237, 18))
    }

    #[test]
    fn colors_writes() {
        assert!(write!(&mut Colors::new(Vec::new()), "hello").is_ok());
    }
}
<|endoftext|>


<commit_before>#![feature(std_misc)]

use std::marker;
use std::thread::scoped;
use std::mem::transmute;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::collections::HashMap;
use std::sync::mpsc::Select;
use std::marker::{PhantomData, PhantomFn};

pub struct Chan<E, T> (Sender<Box<u8>>, Receiver<Box<u8>>, PhantomData<(E, T)>);

fn unsafe_write_chan<A: marker::Send + 'static, E, T>(&Chan(ref tx, _, _): &Chan<E, T>, x: A) {
    let tx: &Sender<Box<A>> = unsafe { transmute(tx) };
    tx.send(Box::new(x)).unwrap();
}

fn unsafe_read_chan<A: marker::Send + 'static, E, T>(&Chan(_, ref rx, _): &Chan<E, T>) -> A {
    let rx: &Receiver<Box<A>> = unsafe { transmute(rx) };
    *rx.recv().unwrap()
}

// Peano numbers needed for Rec and Var
#[allow(missing_copy_implementations)]
pub struct Z;

pub struct S<P> ( PhantomData<P> );

#[allow(missing_copy_implementations)]
pub struct Eps;

pub struct Recv<A,R> ( PhantomData<(A, R)> );

pub struct Send<A,R> ( PhantomData<(A, R)> );

pub struct Choose<R,S> ( PhantomData<(R, S)> );

pub struct Offer<R,S> ( PhantomData<(R, S)> );

pub struct OfferTrait<T> ( PhantomData<T> );

pub struct Rec<R> ( PhantomData<R> );

pub struct Var<V> ( PhantomData<V> );

pub unsafe trait Dual: PhantomFn<Self> {}

unsafe impl Dual for (Eps, Eps) {}

unsafe impl <A, T, U> Dual for (Send<A, T>, Recv<A, U>)
    where (T, U): Dual {}

unsafe impl <A, T, U> Dual for (Recv<A, T>, Send<A, U>)
    where (T, U): Dual {}

unsafe impl<R, S, Rn, Sn> Dual for (Choose<R, Rn>, Offer<S, Sn>)
    where (R, S): Dual, (Rn, Sn): Dual {}

unsafe impl<R, S, Rn, Sn> Dual for (Offer<R, Rn>, Choose<S, Sn>)
    where (R, S): Dual, (Rn, Sn): Dual {}

unsafe impl Dual for (Var<Z>, Var<Z>) {}

unsafe impl<N> Dual for (Var<S<N>>, Var<S<N>>)
    where (Var<N>, Var<N>): Dual {}

unsafe impl<T, U> Dual for (Rec<T>, Rec<U>)
    where (T, U): Dual {}

pub unsafe trait EnvDual: PhantomFn<Self> {}

unsafe impl EnvDual for ((), ()) {}

unsafe impl <R, R_, T, T_> EnvDual for ((R, T), (R_, T_))
    where (R, R_): Dual,
          (T, T_): EnvDual {}

impl<E> Chan<E, Eps> {
    pub fn close(self) {
        // Consume `c`
    }
}

impl<E, T, A: marker::Send + 'static> Chan<E, Send<A, T>> {
    pub fn send(self, v: A) -> Chan<E, T> {
        unsafe_write_chan(&self, v);
        unsafe { transmute(self) }
    }
}

impl<E, T, A: marker::Send + 'static> Chan<E, Recv<A, T>> {
    pub fn recv(self) -> (Chan<E, T>, A) {
        let v = unsafe_read_chan(&self);
        (unsafe { transmute(self) }, v)
    }
}

impl<E, R, S> Chan<E, Choose<R, S>> {
    pub fn sel1(self) -> Chan<E, R> {
        unsafe_write_chan(&self, true);
        unsafe { transmute(self) }
    }

    pub fn sel2(self) -> Chan<E, S> {
        unsafe_write_chan(&self, false);
        unsafe { transmute(self) }
    }
}

impl<Z, A, B> Chan<Z, Choose<A, B>> {
    pub fn skip(self) -> Chan<Z, B> {
        self.sel2()
    }
}

impl<Z, A, B, C> Chan<Z, Choose<A, Choose<B, C>>> {
    pub fn skip2(self) -> Chan<Z, C> {
        self.sel2().sel2()
    }
}

impl<Z, A, B, C, D> Chan<Z, Choose<A, Choose<B, Choose<C, D>>>> {
    pub fn skip3(self) -> Chan<Z, D> {
        self.sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, E>>>>> {
    pub fn skip4(self) -> Chan<Z, E> {
        self.sel2().sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E, F> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, Choose<E, F>>>>>> {
    pub fn skip5(self) -> Chan<Z, F> {
        self.sel2().sel2().sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E, F, G> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, Choose<E, Choose<F, G>>>>>>> {
    pub fn skip6(self) -> Chan<Z, G> {
        self.sel2().sel2().sel2().sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E, F, G, H> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, Choose<E, Choose<F, Choose<G, H>>>>>>>> {
    pub fn skip7(self) -> Chan<Z, H> {
        self.sel2().sel2().sel2().sel2().sel2().sel2().sel2()
    }
}

impl<E, R, S> Chan<E, Offer<R, S>> {
    pub fn offer(self) -> Result<Chan<E, R>, Chan<E, S>> {
        let b = unsafe_read_chan(&self);
        if b {
            Ok(unsafe { transmute(self) })
        } else {
            Err(unsafe { transmute(self) })
        }
    }
}

impl<E, R> Chan<E, Rec<R>> {
    pub fn enter(self) -> Chan<(R, E), R> {
        unsafe { transmute(self) }
    }
}

impl<E, R> Chan<(R, E), Var<Z>> {
    pub fn zero(self) -> Chan<(R, E), R> {
        unsafe { transmute(self) }
    }
}

impl<E, R, V> Chan<(R, E), Var<S<V>>> {
    pub fn succ(self) -> Chan<E, Var<V>> {
        unsafe { transmute(self) }
    }
}

// Homogeneous select. We have a list of channels, all obeying the same protocol
// (and in the exact same point of the protocol)
pub fn hselect<E, P, A>(mut chans: Vec<Chan<E, Recv<A, P>>>) -> (Chan<E, Recv<A, P>>, Vec<Chan<E, Recv<A, P>>>)
{
    let i = iselect(&chans);
    let c = chans.remove(i);
    (c, chans)
}

// An alternative version of homogeneous select, returning the index of the Chan
// that is ready to receive.
pub fn iselect<E, P, A>(chans: &Vec<Chan<E, Recv<A, P>>>) -> usize {
    let mut map = HashMap::new();

    let id = {
        let sel = Select::new();
        let mut handles = vec![]; // collect all the handles

        for (i, chan) in chans.iter().enumerate() {
            let &Chan(_, ref rx, _) = chan;
            let handle = sel.handle(rx);
            map.insert(handle.id(), i);
            handles.push(handle);
        }

        for handle in handles.iter_mut() { // Add
            unsafe { handle.add(); }
        }

        let id = sel.wait();

        for handle in handles.iter_mut() { // Clean up
            unsafe { handle.remove(); }
        }

        id
    };
    map.remove(&id).unwrap()
}

/// Heterogeneous selection structure for channels
///
/// This builds a structure of receiver that we wish to select over. This is a
/// little dangerous, because we transmute the inner Receiver to a 'static
/// lifetime borrow, and if the receiver goes out of scope calling `wait` will
/// most likely cause a crash.
///
pub struct ChanSelect<'c, T> {
    rxs: Vec<&'c Chan<(), ()>>,
    ret: Vec<T>
}

impl<'c, T> ChanSelect<'c, T> {
    pub fn new() -> ChanSelect<'c, T> {
        ChanSelect {
            rxs: Vec::new(),
            ret: Vec::new()
        }
    }

    /// Add a channel whose next step is Recv
    ///
    /// This method is marked unsafe, because of the lifetime transmute. If the
    /// Receiver goes out of scope nasty things can happen.
    pub fn add_ret<E, R, A: marker::Send>(&mut self,
                                               chan: &'c Chan<E, Recv<A, R>>,
                                               ret: T)
    {
        self.ret.push(ret);
        self.rxs.push(unsafe { transmute(chan) });
    }

    /// Find a Receiver (and hence a Chan) that is ready to receive.
    ///
    /// This method consumes the ChanSelect, freeing up the borrowed Receivers
    /// to be consumed.
    pub fn wait(mut self) -> T {
        let sel = Select::new();
        let mut handles = Vec::with_capacity(self.rxs.len());
        let mut map = HashMap::new();

        for (i, chan) in self.rxs.iter().enumerate() {
            let &Chan(_, ref rx, _) = *chan;
            let h = sel.handle(rx);
            let id = h.id();
            map.insert(id, i);
            handles.push(h);
        }

        for handle in handles.iter_mut() {
            unsafe { handle.add(); }
        }

        let id = sel.wait();

        for handle in handles.iter_mut() {
            unsafe { handle.remove(); }
        }
        let index = map.remove(&id).unwrap();
        self.ret.remove(index)
    }
}

impl<'c> ChanSelect<'c, usize> {
    pub fn add<E, R, A: marker::Send>(&mut self,
                                           c: &'c Chan<E, Recv<A, R>>)
    {
        let index = self.rxs.len();
        self.add_ret(c, index);
    }
}

pub fn accept<E: marker::Send + 'static, R: marker::Send + 'static>(tx: Sender<Chan<E, R>>) -> Option<Chan<E, R>> {
    borrow_accept(&tx)
}

pub fn borrow_accept<E: marker::Send + 'static, R: marker::Send + 'static>(tx: &Sender<Chan<E, R>>) -> Option<Chan<E, R>> {
    let (tx1, rx1) = channel();
    let (tx2, rx2) = channel();

    let c1 = Chan (tx1, rx2, PhantomData);
    let c2 = Chan (tx2, rx1, PhantomData);

    match tx.send(c1) {
        Ok(_) => Some(c2),
        _ => None,
    }
}

pub fn request<E: marker::Send + 'static, E_, R: marker::Send + 'static, S>(rx: Receiver<Chan<E, R>>) -> Option<Chan<E_, S>>
    where (R, S): Dual,
          (E, E_): EnvDual
{
    borrow_request(&rx)
}

pub fn borrow_request<E: marker::Send + 'static, E_, R: marker::Send + 'static, S>(rx: &Receiver<Chan<E, R>>) -> Option<Chan<E_, S>>
    where (R, S): Dual,
          (E, E_): EnvDual
{
    match rx.recv() {
        Ok(c) => Some(unsafe { transmute(c) }),
        _ => None,
    }
}

pub fn session_channel<E: marker::Send + 'static, E_, R: marker::Send + 'static, S>() -> (Chan<E, R>, Chan<E_, S>)
    where (R, S): Dual,
          (E, E_): EnvDual
{
    let (tx1, rx1) = channel();
    let (tx2, rx2) = channel();

    let c1 = Chan(tx1, rx2, PhantomData);
    let c2 = Chan(tx2, rx1, PhantomData);

    (c1, c2)
}

pub fn connect<E: marker::Send + 'static, E_, F1, F2, R: marker::Send + 'static, S>(srv: F1, cli: F2)
    where F1: Fn(Chan<E, R>) + marker::Send,
          F2: Fn(Chan<E_, S>) + marker::Send,
          (R, S): Dual,
          (E, E_): EnvDual
{
    let (tx, rx) = channel();
    let joinguard = scoped(move || srv(accept(tx).unwrap()));
    cli(request(rx).unwrap());
    joinguard.join();
}

#[macro_export]
macro_rules! offer {
    (
        $id:ident, $branch:ident => $code:expr, $($t:tt)+
    ) => (
        match $id.offer() {
            Ok($id) => $code,
            Err($id) => offer!{ $id, $($t)+ }
        }
    );
    (
        $id:ident, $branch:ident => $code:expr
    ) => (
        $code
    )
}

#[macro_export]
macro_rules! chan_select {
    (
        $(($c:ident, $name:pat) = $rx:ident.recv() => $code:expr),+
    ) => ({
        let index = {
            let mut sel = $crate::ChanSelect::new();
            $( sel.add(&$rx); )+
            sel.wait()
        };

        let mut i: usize = 0;

        $( if index == { i += 1; i - 1 } { let ($c, $name) = $rx.recv(); $code } else )+
        { unreachable!() }
    })
}
<commit_msg>Add some documentation<commit_after>//! rust-sessions
//!
//! This is an implementation of *session types* in Rust.
//!
//! The channels in Rusts standard library are useful for a great many things,
//! but they're restricted to a single type. Session types allows one to use a
//! single channel for transferring values of different types, depending on the
//! context in which it is used. Specifically, a session typed channel always
//! carry a *protocol*, which dictates how communication is to take place.
//!
//! For example, imagine that two threads, `A` and `B` want to communicate with the following pattern:
//!
//!  1. `A` sends an integer to `B`.
//!  2. `B` sends a boolean to `A` depending on the integer received.
//!
//! With session types, this could be done by sharing a single channel. From
//! `A`'s point of view, it would have the type `int ! (bool ? eps)` where `t ! r`
//! is the protocol "send something of type `t` then proceed with
//! protocol `r`", the protocol `t ? r` is "receive something of type `t` then proceed
//! with protocol `r`, and `eps` is a special marker indicating the end of a
//! communication session.
//!
//! Our session type library allows the user to create channels that adhere to a
//! specified protocol. For example, a channel like the above would have the type
//! `Chan<(), Send<i64, Recv<bool, Eps>>>`, and the full program could look like this:
//!
//! ```
//! extern crate "rust-sessions" as sessions;
//! use sessions::*;
//!
//! type Server = Recv<i64, Send<bool, Eps>>;
//! type Client = Send<i64, Recv<bool, Eps>>;
//!
//! fn srv(c: Chan<(), Server>) {
//!     let (c, n) = c.recv();
//!     if n % 2 == 0 {
//!         c.send(true).close()
//!     } else {
//!         c.send(false).close()
//!     }
//! }
//!
//! fn cli(c: Chan<(), Client>) {
//!     let n = 42;
//!     let c = c.send(n);
//!     let (c, b) = c.recv();
//!
//!     if b {
//!         println!("{} is even", n);
//!     } else {
//!         println!("{} is odd", n);
//!     }
//!
//!     c.close();
//! }
//!
//! fn main() {
//!     connect(srv, cli);
//! }
//! ```

#![feature(std_misc)]

use std::marker;
use std::thread::scoped;
use std::mem::transmute;
use std::sync::mpsc::{Sender, Receiver, channel};
use std::collections::HashMap;
use std::sync::mpsc::Select;
use std::marker::{PhantomData, PhantomFn};

pub struct Chan<E, T> (Sender<Box<u8>>, Receiver<Box<u8>>, PhantomData<(E, T)>);

fn unsafe_write_chan<A: marker::Send + 'static, E, T>(&Chan(ref tx, _, _): &Chan<E, T>, x: A) {
    let tx: &Sender<Box<A>> = unsafe { transmute(tx) };
    tx.send(Box::new(x)).unwrap();
}

fn unsafe_read_chan<A: marker::Send + 'static, E, T>(&Chan(_, ref rx, _): &Chan<E, T>) -> A {
    let rx: &Receiver<Box<A>> = unsafe { transmute(rx) };
    *rx.recv().unwrap()
}

// Peano numbers needed for Rec and Var
#[allow(missing_copy_implementations)]
pub struct Z;

pub struct S<P> ( PhantomData<P> );

#[allow(missing_copy_implementations)]
pub struct Eps;

pub struct Recv<A,R> ( PhantomData<(A, R)> );

pub struct Send<A,R> ( PhantomData<(A, R)> );

pub struct Choose<R,S> ( PhantomData<(R, S)> );

pub struct Offer<R,S> ( PhantomData<(R, S)> );

pub struct OfferTrait<T> ( PhantomData<T> );

pub struct Rec<R> ( PhantomData<R> );

pub struct Var<V> ( PhantomData<V> );

pub unsafe trait Dual: PhantomFn<Self> {}

unsafe impl Dual for (Eps, Eps) {}

unsafe impl <A, T, U> Dual for (Send<A, T>, Recv<A, U>)
    where (T, U): Dual {}

unsafe impl <A, T, U> Dual for (Recv<A, T>, Send<A, U>)
    where (T, U): Dual {}

unsafe impl<R, S, Rn, Sn> Dual for (Choose<R, Rn>, Offer<S, Sn>)
    where (R, S): Dual, (Rn, Sn): Dual {}

unsafe impl<R, S, Rn, Sn> Dual for (Offer<R, Rn>, Choose<S, Sn>)
    where (R, S): Dual, (Rn, Sn): Dual {}

unsafe impl Dual for (Var<Z>, Var<Z>) {}

unsafe impl<N> Dual for (Var<S<N>>, Var<S<N>>)
    where (Var<N>, Var<N>): Dual {}

unsafe impl<T, U> Dual for (Rec<T>, Rec<U>)
    where (T, U): Dual {}

pub unsafe trait EnvDual: PhantomFn<Self> {}

unsafe impl EnvDual for ((), ()) {}

unsafe impl <R, R_, T, T_> EnvDual for ((R, T), (R_, T_))
    where (R, R_): Dual,
          (T, T_): EnvDual {}

impl<E> Chan<E, Eps> {
    pub fn close(self) {
        // Consume `c`
    }
}

impl<E, T, A: marker::Send + 'static> Chan<E, Send<A, T>> {
    pub fn send(self, v: A) -> Chan<E, T> {
        unsafe_write_chan(&self, v);
        unsafe { transmute(self) }
    }
}

impl<E, T, A: marker::Send + 'static> Chan<E, Recv<A, T>> {
    pub fn recv(self) -> (Chan<E, T>, A) {
        let v = unsafe_read_chan(&self);
        (unsafe { transmute(self) }, v)
    }
}

impl<E, R, S> Chan<E, Choose<R, S>> {
    pub fn sel1(self) -> Chan<E, R> {
        unsafe_write_chan(&self, true);
        unsafe { transmute(self) }
    }

    pub fn sel2(self) -> Chan<E, S> {
        unsafe_write_chan(&self, false);
        unsafe { transmute(self) }
    }
}

impl<Z, A, B> Chan<Z, Choose<A, B>> {
    pub fn skip(self) -> Chan<Z, B> {
        self.sel2()
    }
}

impl<Z, A, B, C> Chan<Z, Choose<A, Choose<B, C>>> {
    pub fn skip2(self) -> Chan<Z, C> {
        self.sel2().sel2()
    }
}

impl<Z, A, B, C, D> Chan<Z, Choose<A, Choose<B, Choose<C, D>>>> {
    pub fn skip3(self) -> Chan<Z, D> {
        self.sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, E>>>>> {
    pub fn skip4(self) -> Chan<Z, E> {
        self.sel2().sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E, F> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, Choose<E, F>>>>>> {
    pub fn skip5(self) -> Chan<Z, F> {
        self.sel2().sel2().sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E, F, G> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, Choose<E, Choose<F, G>>>>>>> {
    pub fn skip6(self) -> Chan<Z, G> {
        self.sel2().sel2().sel2().sel2().sel2().sel2()
    }
}

impl<Z, A, B, C, D, E, F, G, H> Chan<Z, Choose<A, Choose<B, Choose<C, Choose<D, Choose<E, Choose<F, Choose<G, H>>>>>>>> {
    pub fn skip7(self) -> Chan<Z, H> {
        self.sel2().sel2().sel2().sel2().sel2().sel2().sel2()
    }
}

impl<E, R, S> Chan<E, Offer<R, S>> {
    pub fn offer(self) -> Result<Chan<E, R>, Chan<E, S>> {
        let b = unsafe_read_chan(&self);
        if b {
            Ok(unsafe { transmute(self) })
        } else {
            Err(unsafe { transmute(self) })
        }
    }
}

impl<E, R> Chan<E, Rec<R>> {
    pub fn enter(self) -> Chan<(R, E), R> {
        unsafe { transmute(self) }
    }
}

impl<E, R> Chan<(R, E), Var<Z>> {
    pub fn zero(self) -> Chan<(R, E), R> {
        unsafe { transmute(self) }
    }
}

impl<E, R, V> Chan<(R, E), Var<S<V>>> {
    pub fn succ(self) -> Chan<E, Var<V>> {
        unsafe { transmute(self) }
    }
}

// Homogeneous select. We have a list of channels, all obeying the same protocol
// (and in the exact same point of the protocol)
pub fn hselect<E, P, A>(mut chans: Vec<Chan<E, Recv<A, P>>>) -> (Chan<E, Recv<A, P>>, Vec<Chan<E, Recv<A, P>>>)
{
    let i = iselect(&chans);
    let c = chans.remove(i);
    (c, chans)
}

// An alternative version of homogeneous select, returning the index of the Chan
// that is ready to receive.
pub fn iselect<E, P, A>(chans: &Vec<Chan<E, Recv<A, P>>>) -> usize {
    let mut map = HashMap::new();

    let id = {
        let sel = Select::new();
        let mut handles = vec![]; // collect all the handles

        for (i, chan) in chans.iter().enumerate() {
            let &Chan(_, ref rx, _) = chan;
            let handle = sel.handle(rx);
            map.insert(handle.id(), i);
            handles.push(handle);
        }

        for handle in handles.iter_mut() { // Add
            unsafe { handle.add(); }
        }

        let id = sel.wait();

        for handle in handles.iter_mut() { // Clean up
            unsafe { handle.remove(); }
        }

        id
    };
    map.remove(&id).unwrap()
}

/// Heterogeneous selection structure for channels
///
/// This builds a structure of receiver that we wish to select over. This is a
/// little dangerous, because we transmute the inner Receiver to a 'static
/// lifetime borrow, and if the receiver goes out of scope calling `wait` will
/// most likely cause a crash.
///
pub struct ChanSelect<'c, T> {
    rxs: Vec<&'c Chan<(), ()>>,
    ret: Vec<T>
}

impl<'c, T> ChanSelect<'c, T> {
    pub fn new() -> ChanSelect<'c, T> {
        ChanSelect {
            rxs: Vec::new(),
            ret: Vec::new()
        }
    }

    /// Add a channel whose next step is Recv
    ///
    /// This method is marked unsafe, because of the lifetime transmute. If the
    /// Receiver goes out of scope nasty things can happen.
    pub fn add_ret<E, R, A: marker::Send>(&mut self,
                                               chan: &'c Chan<E, Recv<A, R>>,
                                               ret: T)
    {
        self.ret.push(ret);
        self.rxs.push(unsafe { transmute(chan) });
    }

    /// Find a Receiver (and hence a Chan) that is ready to receive.
    ///
    /// This method consumes the ChanSelect, freeing up the borrowed Receivers
    /// to be consumed.
    pub fn wait(mut self) -> T {
        let sel = Select::new();
        let mut handles = Vec::with_capacity(self.rxs.len());
        let mut map = HashMap::new();

        for (i, chan) in self.rxs.iter().enumerate() {
            let &Chan(_, ref rx, _) = *chan;
            let h = sel.handle(rx);
            let id = h.id();
            map.insert(id, i);
            handles.push(h);
        }

        for handle in handles.iter_mut() {
            unsafe { handle.add(); }
        }

        let id = sel.wait();

        for handle in handles.iter_mut() {
            unsafe { handle.remove(); }
        }
        let index = map.remove(&id).unwrap();
        self.ret.remove(index)
    }
}

impl<'c> ChanSelect<'c, usize> {
    pub fn add<E, R, A: marker::Send>(&mut self,
                                           c: &'c Chan<E, Recv<A, R>>)
    {
        let index = self.rxs.len();
        self.add_ret(c, index);
    }
}

pub fn accept<E: marker::Send + 'static, R: marker::Send + 'static>(tx: Sender<Chan<E, R>>) -> Option<Chan<E, R>> {
    borrow_accept(&tx)
}

pub fn borrow_accept<E: marker::Send + 'static, R: marker::Send + 'static>(tx: &Sender<Chan<E, R>>) -> Option<Chan<E, R>> {
    let (tx1, rx1) = channel();
    let (tx2, rx2) = channel();

    let c1 = Chan (tx1, rx2, PhantomData);
    let c2 = Chan (tx2, rx1, PhantomData);

    match tx.send(c1) {
        Ok(_) => Some(c2),
        _ => None,
    }
}

pub fn request<E: marker::Send + 'static, E_, R: marker::Send + 'static, S>(rx: Receiver<Chan<E, R>>) -> Option<Chan<E_, S>>
    where (R, S): Dual,
          (E, E_): EnvDual
{
    borrow_request(&rx)
}

pub fn borrow_request<E: marker::Send + 'static, E_, R: marker::Send + 'static, S>(rx: &Receiver<Chan<E, R>>) -> Option<Chan<E_, S>>
    where (R, S): Dual,
          (E, E_): EnvDual
{
    match rx.recv() {
        Ok(c) => Some(unsafe { transmute(c) }),
        _ => None,
    }
}

pub fn session_channel<E: marker::Send + 'static, E_, R: marker::Send + 'static, S>() -> (Chan<E, R>, Chan<E_, S>)
    where (R, S): Dual,
          (E, E_): EnvDual
{
    let (tx1, rx1) = channel();
    let (tx2, rx2) = channel();

    let c1 = Chan(tx1, rx2, PhantomData);
    let c2 = Chan(tx2, rx1, PhantomData);

    (c1, c2)
}

pub fn connect<E: marker::Send + 'static, E_, F1, F2, R: marker::Send + 'static, S>(srv: F1, cli: F2)
    where F1: Fn(Chan<E, R>) + marker::Send,
          F2: Fn(Chan<E_, S>) + marker::Send,
          (R, S): Dual,
          (E, E_): EnvDual
{
    let (tx, rx) = channel();
    let joinguard = scoped(move || srv(accept(tx).unwrap()));
    cli(request(rx).unwrap());
    joinguard.join();
}

#[macro_export]
macro_rules! offer {
    (
        $id:ident, $branch:ident => $code:expr, $($t:tt)+
    ) => (
        match $id.offer() {
            Ok($id) => $code,
            Err($id) => offer!{ $id, $($t)+ }
        }
    );
    (
        $id:ident, $branch:ident => $code:expr
    ) => (
        $code
    )
}

#[macro_export]
macro_rules! chan_select {
    (
        $(($c:ident, $name:pat) = $rx:ident.recv() => $code:expr),+
    ) => ({
        let index = {
            let mut sel = $crate::ChanSelect::new();
            $( sel.add(&$rx); )+
            sel.wait()
        };

        let mut i: usize = 0;

        $( if index == { i += 1; i - 1 } { let ($c, $name) = $rx.recv(); $code } else )+
        { unreachable!() }
    })
}
<|endoftext|>


<commit_before>#![feature(fs, io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    // pub language: Option<String>,
    // pub copyright: Option<String>,
    // pub managing_editor: Option<String>,
    // pub web_master: Option<String>,
    // pub pub_date: Option<String>,
    // pub last_build_date: Option<String>,
    // pub category:
    // pub generator: Option<String>,
    // pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    // pub image: Option<String>,
    // pub rating: Option<String>,
    // pub text_input:
    // pub skip_hours: Option<String>,
    // pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        channel.tag(elem_with_text("title", &self.title));
        channel.tag(elem_with_text("link", &self.link));
        channel.tag(elem_with_text("description", &self.description));

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        }

        channel.items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(channel)
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        if let Some(ref s) = self.title {
            item.tag(elem_with_text("title", s));
        }

        if let Some(ref s) = self.link {
            item.tag(elem_with_text("link", s));
        }

        if let Some(ref s) = self.description {
            item.tag(elem_with_text("description", s));
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        Ok(item)
    }
}

#[cfg(test)]
mod test {
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let Rss(_) = Rss::from_read(&mut file).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel_with_title() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Remove now-stable feature fs<commit_after>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    // pub language: Option<String>,
    // pub copyright: Option<String>,
    // pub managing_editor: Option<String>,
    // pub web_master: Option<String>,
    // pub pub_date: Option<String>,
    // pub last_build_date: Option<String>,
    // pub category:
    // pub generator: Option<String>,
    // pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    // pub image: Option<String>,
    // pub rating: Option<String>,
    // pub text_input:
    // pub skip_hours: Option<String>,
    // pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        channel.tag(elem_with_text("title", &self.title));
        channel.tag(elem_with_text("link", &self.link));
        channel.tag(elem_with_text("description", &self.description));

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        }

        channel.items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(channel)
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        if let Some(ref s) = self.title {
            item.tag(elem_with_text("title", s));
        }

        if let Some(ref s) = self.link {
            item.tag(elem_with_text("link", s));
        }

        if let Some(ref s) = self.description {
            item.tag(elem_with_text("description", s));
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        Ok(item)
    }
}

#[cfg(test)]
mod test {
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let Rss(_) = Rss::from_read(&mut file).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel_with_title() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


<commit_before>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(missing_debug_implementations)]
#![feature(proc_macro, try_from)]
#![recursion_limit="256"]
#![allow(warnings)]

extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate ruma_api;
#[macro_use] extern crate syn;

use proc_macro::TokenStream;
use std::convert::TryFrom;

use quote::{ToTokens, Tokens};

use api::{Api, Exprs};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: hyper::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `hyper::Request` and to create a response from a
/// `hyper::response`.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `hyper::Method`, you just write the value as if it was
///     imported, e.g. `Method::Get`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `hyper::Request`:
///
/// *   `#[ruma_api(header)]`: Fields with this attribute will be treated as HTTP headers on the
///     request.
///     The value must implement `hyper::header::Header`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `hyper::Request`:
///
/// *   `#[ruma_api(header)]`: Fields with this attribute will be treated as HTTP headers on the
///     response.
///     The value must implement `hyper::header::Header`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,no_run
/// #![feature(associated_consts, proc_macro, try_from)]
///
/// extern crate futures;
/// extern crate hyper;
/// extern crate ruma_api;
/// extern crate ruma_api_macros;
/// extern crate serde;
/// #[macro_use] extern crate serde_derive;
/// extern crate serde_json;
/// extern crate serde_urlencoded;
/// extern crate url;
///
/// # fn main() {
/// pub mod some_endpoint {
///     use hyper::header::ContentType;
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: Method::Get,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///             #[ruma_api(header)]
///             pub content_type: ContentType,
///             #[ruma_api(query)]
///             pub bar: String,
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header)]
///             pub content_type: ContentType,
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Debug, Deserialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: Method::Get,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// # }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let exprs: Exprs = syn::parse(input).expect("ruma_api! failed to parse input");

    let api = Api::from(exprs.inner);

    let mut tokens = Tokens::new();

    api.to_tokens(&mut tokens);

    tokens.into()
}
<commit_msg>Simplify code with ToTokens::into_tokens.<commit_after>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(missing_debug_implementations)]
#![feature(proc_macro, try_from)]
#![recursion_limit="256"]
#![allow(warnings)]

extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate ruma_api;
#[macro_use] extern crate syn;

use proc_macro::TokenStream;
use std::convert::TryFrom;

use quote::{ToTokens, Tokens};

use api::{Api, Exprs};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: hyper::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `hyper::Request` and to create a response from a
/// `hyper::response`.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `hyper::Method`, you just write the value as if it was
///     imported, e.g. `Method::Get`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `hyper::Request`:
///
/// *   `#[ruma_api(header)]`: Fields with this attribute will be treated as HTTP headers on the
///     request.
///     The value must implement `hyper::header::Header`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `hyper::Request`:
///
/// *   `#[ruma_api(header)]`: Fields with this attribute will be treated as HTTP headers on the
///     response.
///     The value must implement `hyper::header::Header`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,no_run
/// #![feature(associated_consts, proc_macro, try_from)]
///
/// extern crate futures;
/// extern crate hyper;
/// extern crate ruma_api;
/// extern crate ruma_api_macros;
/// extern crate serde;
/// #[macro_use] extern crate serde_derive;
/// extern crate serde_json;
/// extern crate serde_urlencoded;
/// extern crate url;
///
/// # fn main() {
/// pub mod some_endpoint {
///     use hyper::header::ContentType;
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: Method::Get,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///             #[ruma_api(header)]
///             pub content_type: ContentType,
///             #[ruma_api(query)]
///             pub bar: String,
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header)]
///             pub content_type: ContentType,
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Debug, Deserialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: Method::Get,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// # }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let exprs: Exprs = syn::parse(input).expect("ruma_api! failed to parse input");

    let api = Api::from(exprs.inner);

    api.into_tokens().into()
}
<|endoftext|>


<commit_before>#![allow(let_unit_value, new_without_default, non_snake_case, transmute_ptr_to_ref, type_complexity, unused_imports)]

#[macro_use]
extern crate glib;
extern crate glib_sys as glib_ffi;
extern crate gobject_sys as gobject_ffi;
extern crate gtk;
extern crate libc;

extern crate webkit2gtk_webextension_sys as ffi;

pub use glib::{Error, Object};

macro_rules! assert_initialized_main_thread {
    () => (
        if !::gtk::is_initialized_main_thread() {
            if ::gtk::is_initialized() {
                panic!("GTK may only be used from the main thread.");
            }
            else {
                panic!("GTK has not been initialized. Call `gtk::init` first.");
            }
        }
    )
}

macro_rules! skip_assert_initialized {
    () => ()
}

macro_rules! callback_guard {
    () => (
        let _guard = ::glib::CallbackGuard::new();
    )
}

#[macro_export]
macro_rules! web_extension_init {
    () => {
        extern crate glib;
        extern crate glib_sys;
        extern crate webkit2gtk_webextension_sys;

        #[no_mangle]
        pub unsafe fn webkit_web_extension_initialize_with_user_data(extension: *mut ::webkit2gtk_webextension_sys::WebKitWebExtension, user_data: *mut ::glib_sys::GVariant) {
            web_extension_initialize(::glib::translate::FromGlibPtrNone::from_glib_none(extension), ::glib::translate::FromGlibPtrNone::from_glib_none(user_data));
        }
    };
}

mod auto;
mod dom_dom_selection;
mod dom_dom_window;
mod dom_html_field_set_element;

pub use auto::*;
pub use dom_dom_selection::*;
pub use dom_dom_window::*;
pub use dom_html_field_set_element::*;

unsafe impl Send for WebExtension {}
<commit_msg>Fix formatting<commit_after>#![allow(let_unit_value, new_without_default, non_snake_case, transmute_ptr_to_ref, type_complexity, unused_imports)]

#[macro_use]
extern crate glib;
extern crate glib_sys as glib_ffi;
extern crate gobject_sys as gobject_ffi;
extern crate gtk;
extern crate libc;

extern crate webkit2gtk_webextension_sys as ffi;

pub use glib::{Error, Object};

macro_rules! assert_initialized_main_thread {
    () => (
        if !::gtk::is_initialized_main_thread() {
            if ::gtk::is_initialized() {
                panic!("GTK may only be used from the main thread.");
            }
            else {
                panic!("GTK has not been initialized. Call `gtk::init` first.");
            }
        }
    )
}

macro_rules! skip_assert_initialized {
    () => ()
}

macro_rules! callback_guard {
    () => (
        let _guard = ::glib::CallbackGuard::new();
    )
}

#[macro_export]
macro_rules! web_extension_init {
    () => {
        extern crate glib;
        extern crate glib_sys;
        extern crate webkit2gtk_webextension_sys;

        #[no_mangle]
        #[doc(hidden)]
        pub unsafe fn webkit_web_extension_initialize_with_user_data(
            extension: *mut ::webkit2gtk_webextension_sys::WebKitWebExtension,
            user_data: *mut ::glib_sys::GVariant)
        {
            web_extension_initialize(::glib::translate::FromGlibPtrNone::from_glib_none(extension),
                ::glib::translate::FromGlibPtrNone::from_glib_none(user_data));
        }
    };
}

mod auto;
mod dom_dom_selection;
mod dom_dom_window;
mod dom_html_field_set_element;

pub use auto::*;
pub use dom_dom_selection::*;
pub use dom_dom_window::*;
pub use dom_html_field_set_element::*;

unsafe impl Send for WebExtension {}
<|endoftext|>